Beyond the Gender Wage Gap
Much attention, both academically and journalistically, has been paid to the “Gender Wage Gap” (e.g. http://inequality.stanford.edu/_media/pdf/key_issues/gender_research.pdf). As this is well-tred territory, our team is interested in looking beyond the gender wage gap and analyzing the inter-gender wage gap. That is, within women in the workforce, are there identifiables gaps in earnings? The following report both confirms a gender wage gap across occupations and identifies gaps among several characteristics of women working within each occupation.
Where is the gap?
Since we know there is a significant wage gap between different professions, we used occupation as a category for our data. We seperated the occupations by groups. Within each group, we divided the men and women and compared their weighted mean.
We started by importing the data set from the United States Census Bureau.
#Importing Data Set
# www2.census.gov/programs-surveys/acs/data/pums/2014/1-Year/csv_pus.zip
ss14pusa = read.csv(file.choose(),header=TRUE) # read csv file
ss14pusb = read.csv(file.choose(),header=TRUE)
For our anaylsis, we used dplyr, plyr, dplyr, rcokeh, ggplot2, plotly, car, survey, and googleVis.
The following shows the columns we imported.
attach(ss14pusa)
#names(ss14pusa)
ss14pusa_edit = data.frame(SEX,OCCP,WKHP,MAR,WAGP,SCHL,ESP, RAC1P, ST, PAOC, PWGTP, AGEP)
detach(ss14pusa)
attach(ss14pusb)
ss14pusb_edit = data.frame(SEX,OCCP,WKHP,MAR,WAGP,SCHL,ESP, RAC1P, ST, PAOC, PWGTP, AGEP)
detach(ss14pusb)
Data = rbind(ss14pusa_edit,ss14pusb_edit)
colnames(Data) <- c("Gender","Occupation", "Work_hours", "Marriage", "Income", "Education" ,"Parental_Occupation", "Race", "State", "Children", "Weight","Age")
#write.csv(Data, file = "Data.csv",row.names=TRUE)
#Delete income=0/NA rows
row_to_keep=which(Data$Income>0)
Data=Data[row_to_keep,]
We renamed and categorized multiple categories for readablilty.
Note: we used eight high paying occupation to categorize jobs
attach(ss14pusa)
#names(ss14pusa)
ss14pusa_edit = data.frame(SEX,OCCP,WKHP,MAR,WAGP,SCHL,ESP, RAC1P, ST, PAOC, PWGTP, AGEP)
detach(ss14pusa)
attach(ss14pusb)
ss14pusb_edit = data.frame(SEX,OCCP,WKHP,MAR,WAGP,SCHL,ESP, RAC1P, ST, PAOC, PWGTP, AGEP)
detach(ss14pusb)
Data = rbind(ss14pusa_edit,ss14pusb_edit)
colnames(Data) <- c("Gender","Occupation", "Work_hours", "Marriage", "Income", "Education" ,"Parental_Occupation", "Race", "State", "Children", "Weight","Age")
#write.csv(Data, file = "Data.csv",row.names=TRUE)
#Delete income=0/NA rows
row_to_keep=which(Data$Income>0)
Data=Data[row_to_keep,]
Based on the eight occupations, we plot the weighted mean of men and women to compare the gap.
NAs introduced by coercionNAs introduced by coercion
From the graph, we see there is a significant difference between men and women over all occupations. To gain a better understanding we graphed them by percentage from the weighted mean of both genders.
#median wage for each occupation by gender (just to acknowledge that there *is* a gender gap)
Data_sex_occp <- ddply(Data, .(Gender, Occupation), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
ggplot(Data_sex_occp, aes(x=Occupation, y=MEAN, fill=factor(Gender))) +
geom_bar(stat="identity",position="dodge") +
scale_fill_brewer(palette="RdYlGn") +
labs(fill="") +
ylab("Mean Salary ($)") +
xlab("Occupations") +
ggtitle(paste("Salary Comparison between Men & Women")) +
theme(axis.text.x = element_text(angle = 30, hjust = 1),
panel.background = element_rect(fill = 'white' )) +
theme_grey(base_size = 12)

Oberservations:
Medical occupations has the largest disperity between men and women
Women in legal occupations are the closest to the median
In this report, we will investigate 5 probable causes to determine which groups of women will most likely succeed or fail. These categories are: Marriage Status, Motherhood, Location, Race, and Education.
Familial Responsibilities
Our next variable of interest is women’s marital statuses. A common explanation of the gender wage gap is that women make the decision with their families to shift their focus to household responsibilities. We’ll be looking at the effect of marriage and motherhood seperately first, then looking how marital statuses of mothers affect their earnings.
Marital Status
Below we analyse the effect of marital status on mean income for women across all occupations, as well as within occupations.
Observations:
Overall,widowed and seperated women make significantly less than married women when occupations are pooled.
Marital status has no effect on earning for women in the scientific field
Interestingly, for most occupations where marital status is significant, women in their profession who have never been married earn more than married women, whereas widowed and seperated women earn significantly less. Perhaps widowed or seperated women are more likely to have children than never married women, and thus must shoulder more responsibilities outside of work.
Motherhood
After investigating how marriage status affect women’s income, we looked into the presence and age of children owned by the women to determine how it might correlate to women’s income. We expect women with Children under 6 may have less working hours and thus lower income (reasoning: when a child is young the women of the house is more likely to stay home with their children. As we see the children grow, we expect a trend for women to earn the higher.) Furthermore, we may also want to figure out how occupation and age for women with children affect their income.
At first, we want to have a glance at the income level of the different groups of females. Basically females are divided into four categories regarding the presence and age of Children: Females with Children under 6, Females with Children from 6 to 17, Females with Children under 6 and above 6, Females with No Children. Thus we simply creat a bar chart to illustrate the income difference.
#marital status, subset at specific age to control for experience
Data_women <- filter(Data, Gender == 2)
Data_wed_occp <- ddply(Data_women, .(Marriage, Occupation, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
plot(Data_wed_occp$Age, Data_wed_occp$MEAN)

summary(lm(MEAN ~ Marriage + Age + I(Age^2) , data = Data_wed_occp))
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_occp)
Residuals:
Min 1Q Median 3Q Max
-56107 -11573 -1470 8035 231989
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -39977.664 3357.450 -11.907 < 2e-16 ***
MarriageWidowed -5058.692 1430.698 -3.536 0.000415 ***
MarriageDivorced -3058.190 1342.701 -2.278 0.022842 *
MarriageSeperated -8106.266 1479.165 -5.480 4.72e-08 ***
MarriageNever Married 557.144 1337.027 0.417 0.676935
Age 4089.016 134.708 30.355 < 2e-16 ***
I(Age^2) -38.882 1.275 -30.488 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 21170 on 2232 degrees of freedom
Multiple R-squared: 0.2979, Adjusted R-squared: 0.296
F-statistic: 157.8 on 6 and 2232 DF, p-value: < 2.2e-16
#Finance
Women_FIN<-filter(Data_women, Occupation =="FIN")
Data_wed_FIN <- ddply(Women_FIN, .(Marriage, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
FIN <- plot_ly(Data_wed_FIN, x = Age, y = MEAN, mode = "markers", opacity = .4, color = Marriage, title = "Women in Finance")
FIN <-add_trace(FIN,y = fitted(loess(MEAN ~ Age + as.numeric(Marriage))) , x = Age, color = Marriage)
layout(FIN, title = "Women in Finance")
summary(lm(MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_FIN))
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_FIN)
Residuals:
Min 1Q Median 3Q Max
-35099 -8154 -769 6758 85196
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -36346.096 6420.514 -5.661 3.61e-08 ***
MarriageWidowed -7156.318 2631.738 -2.719 0.00694 **
MarriageDivorced -2261.388 2542.871 -0.889 0.37457
MarriageSeperated -15267.284 2763.424 -5.525 7.33e-08 ***
MarriageNever Married 2543.383 2558.912 0.994 0.32108
Age 3941.532 258.084 15.272 < 2e-16 ***
I(Age^2) -39.041 2.435 -16.032 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 14470 on 291 degrees of freedom
Multiple R-squared: 0.5055, Adjusted R-squared: 0.4953
F-statistic: 49.57 on 6 and 291 DF, p-value: < 2.2e-16
#Engineering
Women_ENG<-filter(Data_women, Occupation =="ENG")
Data_wed_ENG <- ddply(Women_ENG, .(Marriage, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
#plotly
ENG <- plot_ly(Data_wed_ENG, x = Age, y = MEAN, mode = "markers", opacity = .4, color = Marriage, title = "Women in Finance")
ENG <-add_trace(ENG,y = fitted(loess(MEAN ~ Age + as.numeric(Marriage))) , x = Age, color = Marriage)
layout(ENG, title = "Women in Engineering")
lm1 <- lm(MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_ENG)
summary(lm1)
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_ENG)
Residuals:
Min 1Q Median 3Q Max
-71787 -13616 -1922 6880 221919
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -67401.667 18767.237 -3.591 0.000411 ***
MarriageWidowed -1410.202 7393.487 -0.191 0.848921
MarriageDivorced -4852.957 6009.505 -0.808 0.420283
MarriageSeperated -16473.248 7418.879 -2.220 0.027478 *
MarriageNever Married -1392.858 5878.545 -0.237 0.812939
Age 5917.840 827.959 7.148 1.50e-11 ***
I(Age^2) -59.961 8.655 -6.928 5.36e-11 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 30550 on 206 degrees of freedom
Multiple R-squared: 0.2152, Adjusted R-squared: 0.1924
F-statistic: 9.416 on 6 and 206 DF, p-value: 3.912e-09
#Medicine
Women_MED<-filter(Data_women, Occupation =="MED")
Data_wed_MED <- ddply(Women_MED, .(Marriage, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
#plotly
MED <- plot_ly(Data_wed_MED, x = Age, y = MEAN, mode = "markers", opacity = .4, color = Marriage, title = "Women in Finance")
MED <-add_trace(MED,y = fitted(loess(MEAN ~ Age + as.numeric(Marriage))) , x = Age, color = Marriage)
layout(MED, title = "Women in Finance")
summary(lm(MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_MED))
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_MED)
Residuals:
Min 1Q Median 3Q Max
-35762 -7890 447 6423 117974
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -19061.330 6542.696 -2.913 0.003825 **
MarriageWidowed -10048.240 2875.561 -3.494 0.000542 ***
MarriageDivorced -1420.377 2803.367 -0.507 0.612733
MarriageSeperated -9171.092 3002.385 -3.055 0.002441 **
MarriageNever Married -419.022 2828.361 -0.148 0.882317
Age 3019.839 255.543 11.817 < 2e-16 ***
I(Age^2) -28.188 2.342 -12.037 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 16640 on 323 degrees of freedom
Multiple R-squared: 0.3316, Adjusted R-squared: 0.3192
F-statistic: 26.7 on 6 and 323 DF, p-value: < 2.2e-16
#Science
Women_SCI<-filter(Data_women, Occupation =="SCI")
Data_wed_SCI <- ddply(Women_SCI, .(Marriage, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
#plotly
SCI <- plot_ly(Data_wed_SCI, x = Age, y = MEAN, mode = "markers", opacity = .4, color = Marriage, title = "Women in Science")
SCI <-add_trace(SCI,y = fitted(loess(MEAN ~ Age + as.numeric(Marriage))) , x = Age, color = Marriage)
layout(SCI, title = "Women in Science")
summary(lm(MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_SCI))
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_SCI)
Residuals:
Min 1Q Median 3Q Max
-68959 -10504 -932 8858 95689
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -77292.909 10726.610 -7.206 7.04e-12 ***
MarriageWidowed -6390.342 4489.513 -1.423 0.156
MarriageDivorced -2419.314 3934.713 -0.615 0.539
MarriageSeperated 2882.259 4602.021 0.626 0.532
MarriageNever Married 2465.396 3899.844 0.632 0.528
Age 5640.076 444.813 12.680 < 2e-16 ***
I(Age^2) -53.246 4.334 -12.286 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 21450 on 246 degrees of freedom
Multiple R-squared: 0.4066, Adjusted R-squared: 0.3922
F-statistic: 28.1 on 6 and 246 DF, p-value: < 2.2e-16
#Managers
Women_MGR<-filter(Data_women, Occupation =="MGR")
Data_wed_MGR <- ddply(Women_MGR, .(Marriage, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
MGR <- plot_ly(Data_wed_MGR, x = Age, y = MEAN, mode = "markers", opacity = .4, color = Marriage, title = "Women in Management")
MGR <-add_trace(MGR,y = fitted(loess(MEAN ~ Age + as.numeric(Marriage))) , x = Age, color = Marriage)
layout(MGR, title = "Women in Management")
summary(lm(MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_MGR))
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_MGR)
Residuals:
Min 1Q Median 3Q Max
-40481 -9893 -582 5931 212526
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -44162.963 8226.978 -5.368 1.51e-07 ***
MarriageWidowed -2612.919 3617.947 -0.722 0.4707
MarriageDivorced -4895.286 3620.382 -1.352 0.1773
MarriageSeperated -8413.422 3807.248 -2.210 0.0278 *
MarriageNever Married -1116.802 3591.031 -0.311 0.7560
Age 4377.509 326.101 13.424 < 2e-16 ***
I(Age^2) -40.301 3.009 -13.391 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 21380 on 327 degrees of freedom
Multiple R-squared: 0.3585, Adjusted R-squared: 0.3467
F-statistic: 30.46 on 6 and 327 DF, p-value: < 2.2e-16
#Lawyers
Women_LGL<-filter(Data_women, Occupation =="LGL")
Data_wed_LGL <- ddply(Women_LGL, .(Marriage, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
LGL <- plot_ly(Data_wed_LGL, x = Age, y = MEAN, mode = "markers", opacity = .4, color = Marriage)
LGL <-add_trace(LGL,y = fitted(loess(MEAN ~ Age + as.numeric(Marriage))) , x = Age, color = Marriage)
layout(LGL, title = "Women in Law")
summary(lm(MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_LGL))
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_LGL)
Residuals:
Min 1Q Median 3Q Max
-38365 -8400 -2126 6518 159634
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -39807.860 9552.619 -4.167 4.26e-05 ***
MarriageWidowed -11672.166 3875.330 -3.012 0.00286 **
MarriageDivorced -4590.456 3398.000 -1.351 0.17795
MarriageSeperated -3691.867 3913.706 -0.943 0.34644
MarriageNever Married 50.710 3386.857 0.015 0.98807
Age 3548.182 390.813 9.079 < 2e-16 ***
I(Age^2) -32.067 3.797 -8.446 2.56e-15 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 18510 on 248 degrees of freedom
Multiple R-squared: 0.274, Adjusted R-squared: 0.2565
F-statistic: 15.6 on 6 and 248 DF, p-value: 3.508e-15
#Business
Women_BUS<-filter(Data_women, Occupation =="BUS")
Data_wed_BUS <- ddply(Women_BUS, .(Marriage, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
BUS <- plot_ly(Data_wed_BUS, x = Age, y = MEAN, mode = "markers", opacity = .4, color = Marriage)
BUS <-add_trace(BUS,y = fitted(loess(MEAN ~ Age + as.numeric(Marriage))) , x = Age, color = Marriage)
layout(BUS, title = "Women in Business")
summary(lm(MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_BUS))
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_BUS)
Residuals:
Min 1Q Median 3Q Max
-40066 -10052 -1659 6642 173126
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -33142.936 8924.930 -3.714 0.000246 ***
MarriageWidowed 2308.734 3704.024 0.623 0.533580
MarriageDivorced -1095.901 3625.929 -0.302 0.762688
MarriageSeperated -10299.949 3862.286 -2.667 0.008092 **
MarriageNever Married 3826.334 3582.032 1.068 0.286327
Age 3701.176 355.322 10.416 < 2e-16 ***
I(Age^2) -36.125 3.345 -10.800 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 20210 on 287 degrees of freedom
Multiple R-squared: 0.303, Adjusted R-squared: 0.2884
F-statistic: 20.79 on 6 and 287 DF, p-value: < 2.2e-16
#Computer
Women_CMM<-filter(Data_women, Occupation =="CMM")
Data_wed_CMM <- ddply(Women_CMM, .(Marriage, Age), summarise, MEAN = weighted.mean(Income, Weight, na.rm = T))
CMM <- plot_ly(Data_wed_CMM, x = Age, y = MEAN, mode = "markers", opacity = .4, color = Marriage)
CMM <-add_trace(CMM,y = fitted(loess(MEAN ~ Age + as.numeric(Marriage))) , x = Age, color = Marriage)
layout(CMM, title = "Women in Law")
summary(lm(MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_CMM))
Call:
lm(formula = MEAN ~ Marriage + Age + I(Age^2), data = Data_wed_CMM)
Residuals:
Min 1Q Median 3Q Max
-49094 -9844 78 6958 121180
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -47534.01 8781.27 -5.413 1.43e-07 ***
MarriageWidowed -2742.11 3575.69 -0.767 0.444
MarriageDivorced -2754.09 3335.19 -0.826 0.410
MarriageSeperated -4313.13 3625.43 -1.190 0.235
MarriageNever Married -1096.28 3334.11 -0.329 0.743
Age 4792.97 364.29 13.157 < 2e-16 ***
I(Age^2) -46.82 3.59 -13.041 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 18000 on 255 degrees of freedom
Multiple R-squared: 0.4061, Adjusted R-squared: 0.3921
F-statistic: 29.06 on 6 and 255 DF, p-value: < 2.2e-16
Observations:
1.Women with children 6 to 17 has obviously higher Average Income as they have more working experience and do not need to spend too much time to take care of young children.
2.Women with Children of both ages have slightly lower income, which is also reasonable as they may not have too much time in work.
The bar chart verifies our guess. Next, in order to better understand why women with children 6 to 17 have higher income and whether it has anything to do with age, we are going to study how the income change for different groups of women through out age. Basically we try to analyze by line chart to see the income trend and compare.
Data_women <- filter(Data, Gender == 2)
Data_women$Agegroup <- cut(as.numeric(Data_women$Age), breaks = c(20,25,30,35,40,45,50,55,60,65))
Data_women <- filter(Data_women, Age > 20 & Age < 66)
### Line Chart with regard to Age
MotherHood=select(Data_women, Income,Children,Agegroup)
#detach(package:plyr)
GroupedMotherHood <-
MotherHood %>%
na.omit() %>%
group_by(Children,Agegroup) %>%
summarize(
AvgIncome = mean(Income)
)
GroupedMotherHood$Children<-factor(GroupedMotherHood$Children, levels = c("1","2","3","4"), c('Children under 6','Children from 6 to 17','Children under 6 and above 6','No Children'))
Error in `$<-.data.frame`(`*tmp*`, "Children", value = integer(0)) :
replacement has 0 rows, data has 1
Observations:
Before 45-50 years old, there is an abvious increasing trend of income basically for all groups. And after that age, average income begins to decrease or stablize.
Surprisingly, for the same age group, women with Children under 6 have higher income. While women with children from 6 and 17 have higher income after 45 years old, which might be the reason this group has higher average income. On the other hand, women with no children doesn’t earn less than other groups at younger age groups, but their income become stable and less than others after 40 years old.
Next, we wanted to see how the working hours related to the income of women in different group. Will women with children from 6 to 17 have more working hours and generate higher income? Thus we want to use bubble chart to integrate working hours, average income, the group count in a bubble chart so that all the information can be gained in the same graph.
#ggplot(GroupedMotherHood, aes(x=Agegroup, y=AvgIncome,fill=Children)) +
# geom_bar(width=.5, stat="identity")+
# xlab("Age Group") + ylab("Mean Income") +
# ggtitle("Income for Motherhood")
ggplot(GroupedMotherHood, aes(x=Agegroup, y=AvgIncome,group=Children,colour=Children)) +
geom_line()+
geom_point()+
#guides(fill=FALSE) +
xlab("Age Group") + ylab("Mean Income") +
ggtitle("Income for Motherhood")

Observations:
When work_hours smaller than 60Hrs, Avg Income tend to be positively related to work hour, which agrees with our common knowledge. Most women concentrate around 40 working hours.
There are generally more females with no Children in this survey as green circles are generally larger in size. Also it can be observed there are much more women with no children working more than 50 hours compared to other groups. On the other hand, there are basically less women with children from both age groups.
Females with Children from 6 to 17 often have higher avg income. While for the same working hour level, females with no children are frequently have lower average income.
Next we want to investigate whether the income difference among four grouops of female have any relationship to their occupation. Therefore we use this chart to compare the income for four groups of women in different occupations. Basically, darker color represent higher income and larger size indicate larger group size.
MotherWorking=select(Data_women, Income,Children,Work_hours)
#detach(package:plyr)
GroupedMotherWorking <-
MotherWorking %>%
na.omit() %>%
group_by(Children,Work_hours) %>%
summarize(AvgIncome = mean(Income), count=n())
GroupedMotherWorking$Children<-factor(GroupedMotherWorking$Children, levels = c("1","2","3","4"),labels= c('Children under 6','Children from 6 to 17','Children under 6 and above 6','No Children'))
# note how size is automatically scaled and added as hover text
plot_ly(GroupedMotherWorking, x = Work_hours, y = AvgIncome,size=sqrt(count), color = Children,mode = "markers",hoverinfo = "text",text = paste("AvgIncome:",AvgIncome,"<br>","Count:",count,"<br>"))
Marital statuses of mothers

Observations: We can see in the summary results of the interaction between marital status and motherhood, single mothers earn significantly less when occupations are pooled and age is controlled.
Education
We expect that educational attainment would affect the women’s income. We may want to figure out which degree is the most important factor to earn more than the median income. Furthermore, we will see which occupation has the largest/smallest “below median group” within each educational attainment.
We divided female into 2 groups (>=$60,000 vs <60,000) using weighted median income for working class. ($60,000) We will see the proportion of these 2 groups for each educational attainment.
MotherMaritalOccupation=select(Data_women, Income,Children,Occupation, Marriage, Age)
MotherMaritalOccupation <- na.omit(MotherMaritalOccupation)
MotherMaritalOccupation$Children <- ifelse(MotherMaritalOccupation$Children == 4, 0, 1)
#detach(package:plyr)
GroupedMotherMaritalOccupation <-
MotherMaritalOccupation %>%
na.omit() %>%
group_by(Children,Occupation, Marriage, Age) %>%
summarize(
AvgIncome = mean(Income),
count=n()
)
GroupedMotherMarital <-
MotherMaritalOccupation %>%
na.omit() %>%
group_by(Children, Marriage, Age) %>%
summarize(
AvgIncome = mean(Income),
count=n()
)
ggplot(GroupedMotherMarital,aes(y = AvgIncome, x =Age,colour=as.factor(Children))) +
geom_point() + geom_smooth(method="loess", fill=NA) + facet_wrap(~Marriage, scales= "free")

summary(lm(AvgIncome ~ Age + I(Age^2) + Children*Marriage, data = GroupedMotherMaritalOccupation))
Call:
lm(formula = AvgIncome ~ Age + I(Age^2) + Children * Marriage,
data = GroupedMotherMaritalOccupation)
Residuals:
Min 1Q Median 3Q Max
-65888 -10493 -1879 7328 384166
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -59323.906 5257.629 -11.283 < 2e-16 ***
Age 4987.877 254.145 19.626 < 2e-16 ***
I(Age^2) -47.777 2.929 -16.313 < 2e-16 ***
Children 2882.840 1628.541 1.770 0.076801 .
MarriageWidowed -6785.321 1847.179 -3.673 0.000244 ***
MarriageDivorced -2517.617 1618.366 -1.556 0.119902
MarriageSeperated -8634.582 1722.751 -5.012 5.71e-07 ***
MarriageNever Married 3243.048 1600.407 2.026 0.042818 *
Children:MarriageWidowed -6511.152 2805.557 -2.321 0.020368 *
Children:MarriageDivorced -4680.108 2365.606 -1.978 0.047980 *
Children:MarriageSeperated -1087.083 2514.920 -0.432 0.665590
Children:MarriageNever Married -10540.040 2354.884 -4.476 7.91e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 21470 on 2842 degrees of freedom
Multiple R-squared: 0.2619, Adjusted R-squared: 0.2591
F-statistic: 91.69 on 11 and 2842 DF, p-value: < 2.2e-16
Observations:
Without college degree, about 80% of them earn less than median income.
With master’s or doctor’s degree, about 40% of them earn less than median income.
Next, we use a linear regression.
#Calculate weighted median to split income below/above
Data_w<-svydesign(id = ~1, weights = ~Data$Weight, data = Data)
svyquantile(~Data$Income, Data_w, c(.25,.5,.75))
0.25 0.5 0.75
Data$Income 35000 60000 92000
##Median income=$60000
#split income below/above
Data$Income_m<-ifelse(Data$Income>=60000,">=$60,000","<$60,000")
Data_women2<-subset(Data,Gender=='2')
attach(Data_women2)
The following objects are masked from Data_women2 (pos = 3):
Age, Children, Division, Education, Gender, Income, Marriage, Occupation, Parental_Occupation, Race, Region,
State, Weight, Work_hours
The following objects are masked from Data_women2 (pos = 4):
Age, Children, Division, Education, Gender, Income, Marriage, Occupation, Parental_Occupation, Race, Region,
State, Weight, Work_hours
Data_women2<-data.frame(Education,Occupation,Income_m,Weight)
detach(Data_women2)
#get the summary table-education
Data_women_w<-svydesign(id = ~1, weights = ~Data_women2$Weight, data = Data_women2)
t1<-prop.table(svytable(~Income_m+Education, Data_women_w),2)
barplot(t1, main = "Below/Above median income women by Educational attainment",col = c("mistyrose", "lavender"),
xlab = "Educational attainment", names = c("~g8", "g9~nodegree","ass/bach","prof/mas","doc"),
ylab = "proportion", legend = c("<$60,000", ">=$60,000"),
args.legend = list(title = "income", x = "topright", cex = 1), ylim = c(0, 1.5))

Observations:
factor2 (grade9~college_no_degree) is not significant.
Interpretation for factor3: “associate/bachelor’s degree”, versus “~grade8”(baseline), multiplies the odds of being “>=$60000” group by exp(0.94372)
We can apply the same interpretation for factor 4,5,6.
Within college, master, doctor’s degree, the chance of being in “>=$60000” group increases at higher educational attainment.
However, the gap between master’s and doctor’s degree is relatively small.
To futher understand the effect, we are going to break down each education by occupation.
fit_edu<-svyglm(factor(Income_m) ~ factor(Education), design = Data_women_w,family=binomial)
non-integer #successes in a binomial glm!
summary(fit_edu)
Call:
svyglm(formula = factor(Income_m) ~ factor(Education), design = Data_women_w,
family = binomial)
Survey design:
svydesign(id = ~1, weights = ~Data_women2$Weight, data = Data_women2)
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.30179 0.11634 -11.189 < 2e-16 ***
factor(Education)2 -0.06833 0.11711 -0.584 0.56
factor(Education)3 0.94372 0.11663 8.091 5.94e-16 ***
factor(Education)4 1.78284 0.11708 15.228 < 2e-16 ***
factor(Education)5 2.03576 0.12210 16.673 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1.000005)
Number of Fisher Scoring iterations: 4
Observations:
Within “~grade8”, “FIN:finance” has the largest <$60,000 group.
“CMM:computer occs” has the smallest <$60,000 group.

Observations:
Within “grade9~college_no_degree”, “SCI:science” has the largest <$60,000 group.
“CMM:computer occs” has the smallest <$60,000 group.

Observations:
Within “associate/bachelor”, “LGL:legal” has the largest <$60,000 group.
“CMM: computer occs” has the smallest <$60,000 group.

Observations:
Within “Master”, “LGL:legal” has the largest <$60,000 group.
“CMM:computer occs” has the smallest <$60,000 group.

Observations:
Within “Doctor”, “LGL:legal” has the largest <$60,000 group.
“CMM:computer occs” has the smallest <$60,000 group.
Conclusions:
Women without college degree is more likely to earn less than median income.
(-) At any educational attainment,CMM:computer occs has the smallest <$60,000 group.
(+) With the bachelor/master/doctor’s degree LGL:legal has the largest >=$60,000 group.
Regional
You cannot choose where you were born, but you can choose where you live. Different places sends different messages and attracts different people. In this section we are interested to see regional effect on women’s income in the US. The main question here is: in which locations are women better or worse off?
First, we want to look at women’s income boxplots in all 4 regions to better understand women’s income distribution.

The boxplots of women’s income show that despite that all distributions are highly skewed to the right, the Northeast Region has the highest women’s income level of all 4 regions, followed by the West; Midwest has the lowest women’s income level, whereas South is only slightly better off than that. Then we will break down to state level to investigate further on women’s income level.
Income levels can be affected by many things. Cost of living is one of them. For example, In New York, everthing cost a little more than many other parts of the US, so people will only thrive by earning more money. Therefore, in order to remove the effect of cost of living that differs in different states, we calculate the percentage of median of each woman’s income by state and draw boxplot according to that.
From this irisdescent boxplot by state, we can see that New York definitely goes ahead (despite that its cost of living is already high), so does Connecticut with more large extreme values; however California has the highest upper whisker and largest portion of upper middle income; Utah and Wyoming are the worst off.
Then we want to decide locations where women will thrive most financially (relatively to men), so we plot women’s median of percentage income by state in a US map, which shows the percentage of statewise median that half of women has income below. In perfect equal-gender scenarios, the percentage should be 1, which means half of women have income below the exact statewise median.
This map clearly shows that Utah is where women thrive most financially (relatively to men). Half of women in Utah have income below 68.97% of state median, compared to 100% in the perfect equal-gender situation. Surprisingly (at least to us), D.C. tops among all states with a 93%, followed by Nevada 92% and Arizona 90%.
Observation: Women’s income distributions in each state are all highly skewed to the right with lots of large extreme values.
The Northeast Region has the highest women’s income level of all 4 regions in the US.
After excluding statewise differences e.g. cost of living, women in New York and Connecticut tend to have higher incomes, California has the highest upper whisker and largest portion of upper middle income, and Utah and Wyoming are the worst off.
By comparing women’s income medians with state medians, we see that half of Utah’s women have income below 69% of state median, which is the lowest percentage among all states. Woman in D.C., Nevada, and Arizona have income medians closest to state median, with percentage above 90%, whereas other states’ are much lower.
Race
Over the years, there has been an increase awareness on the women wage gap and racial social issues. We wanted to understand the effects of a women’s race could potentially have on a women’s career.
First, we broke down the data of women by race.
# Map women's median of percentage of median by state
PercM <- aggregate(Percentage_of_Median~State,Perc, median)
names(PercM)[1]<-"name"
PM <- merge(PercM, statenames, by="name")
# light grey boundaries
l <- list(color = toRGB("white"), width = 1)
# specify some map projection/options
g <- list(
scope = 'usa',
projection = list(type = 'albers usa'),
showlakes = TRUE,
lakecolor = toRGB('white')
)
plot_ly(PM, z = Percentage_of_Median, locations = abbr, text=name, type = 'choropleth',
locationmode = 'USA-states', color = Percentage_of_Median, colors = 'Blues',
marker = list(line = l), colorbar = list(title = "Median Percentage")) %>%
layout(title = '2014 Median of Woman Percentage Income by State', geo = g)
Error in seq.default(min(rng), max(rng), length.out = 10) :
'from' cannot be NA, NaN or infinite
From the pie chart, we determined that majority of women in the work force are white. To see how this compares to the national average, we compared this chart to the overall race breakdown of the country. Our assumption is that women should make up half of the working force for all races.
Race_freq <- ftable(Data_Women$Race)
Race_freq <- as.data.frame(Race_freq)
plot_ly(Race_freq, labels = Var1, values = Freq, type = "pie",hole = 0.0,name = "Race") %>%
layout(title = "Percentage of Women by Race")
Observation:
From the table, we can gather that Black women are 11% higher than the half of the Black workforce. This means more black women are working than man.
All other races have a relatively small difference.
Workforce groups with more men than women are White, Asian, and Others.
We also want to look into how women perform in the occupation. We broke up this into three categories:
Women who perform under the weighted mean of women
Women who perform above the weighted mean of both genders
Women who perform above the weighted mean of men
These categories will be classified as below, meet, and exceed respectively.
Race_freq_All <- ftable(Data$Race)
Race_freq_All <- as.data.frame(Race_freq_All)
Race_Compare <- data.frame(Race_freq$Var1,Race_freq$Freq,0.5 *Race_freq_All$Freq,100*(Race_freq$Freq-0.5 *Race_freq_All$Freq)/Race_freq_All$Freq)
colnames(Race_Compare) <- c('Race','Women','50% of General population','Percentage Difference (%)')
Race_Compare
From the graph, we notices that majority of occupation were not meeting the criteria. To gain a better understand, we took into account he population size.
#Comparing with Histograms
DSOR_W <- data.frame(Data_sex_occp_race[which(Data_sex_occp_race$Gender==2),])
p <- ggplot(DSOR_W, aes(x=Race,y=MEAN, fill=factor(Race))) +
geom_bar(position = "dodge",stat="identity")+
facet_grid(. ~ Occupation)+
geom_hline(aes(yintercept = MEAN),data=Data_sex_occp_women)+
geom_text(aes(1,0.5,label = "Women's Mean"))+
labs(title = "Histogram by Race of Females compared to Women's Mean")
ggplotly(p)
is.na() applied to non-(list or vector) of type 'NULL'is.na() applied to non-(list or vector) of type 'NULL'is.na() applied to non-(list or vector) of type 'NULL'is.na() applied to non-(list or vector) of type 'NULL'is.na() applied to non-(list or vector) of type 'NULL'is.na() applied to non-(list or vector) of type 'NULL'is.na() applied to non-(list or vector) of type 'NULL'is.na() applied to non-(list or vector) of type 'NULL'
Oberservations:
Asians women earn significantly higher income than other races.
The average for women is very close the White women because they account for most of the workforce.
There are no groups of women that are higher than the median of men
From the plot, we also see a lot of minority groups toward the bottom. The frequency for these froups were often very small. To help gain a better understanding, we took out all groups with less than 50 people in the category.
x <- ftable(Data_Women$Race,Data_Women$Occupation)
x <- as.data.frame(x)
x <- x[-31,] #frequency of zero
DSOR_W_Freq <- data.frame(DSOR_W,x$Freq)
Base <- ggplot(DSOR_W_Freq, aes(x=Race,y=MEAN),colour = factor(DSOR_W_Freq$Race)) +
facet_grid(. ~ Occupation)+
geom_point(aes(size = DSOR_W_Freq$x.Freq,color = factor(DSOR_W_Freq$Race)))+
labs(title = "Histogram by Race of Females using Size")+
geom_hline(aes(yintercept = MEAN),colour="deeppink1",data=Data_sex_occp_women)+
geom_hline(aes(yintercept = MEAN),colour="blue",data=Data_sex_occp_men)+
geom_hline(aes(yintercept = MEAN),colour="green",data=Data_occu)
ggplotly(Base)
Obeservations:
Except for Asians and Blacks, all other minority groups earned significantly less than the median.
Black Women earn less than White womens for all occupations, except legal.
Lawyers would have the most equal pay relative to the rest of the occupations.
From our analysis, we learned the following breakdown of women in the workforce:
| Below |
Black, American Indian, Tribe specified, Native Hawaiian, Other, Two or more races |
| Meet |
Asian, White |
| Exceed |
None |
Through these results, their is a significant gap in income for women regardless to race.
Appendix
Using Survey Weights
We were trying to determine whether or not to use survey weights? Would the data be significantly impacted?
DSOR_W_Freq_filtered <- filter(DSOR_W_Freq, x.Freq > 50)
Base_fill <- ggplot(DSOR_W_Freq_filtered, aes(x=Race,y=MEAN),colour = factor(DSOR_W_Freq_filtered$Race)) +
facet_grid(. ~ Occupation)+
geom_point(aes(size = DSOR_W_Freq_filtered$x.Freq,color = factor(DSOR_W_Freq_filtered$Race)))+
labs(title = "Histogram by Race of Females using Size")+
geom_hline(aes(yintercept = MEAN),colour="deeppink1",data=Data_sex_occp_women)+
geom_hline(aes(yintercept = MEAN),colour="blue",data=Data_sex_occp_men)+
geom_hline(aes(yintercept = MEAN),colour="green",data=Data_occu)
ggplotly(Base_fill)
From our results, the survey weights would be insignificant relative to the data. The difference for each income level between unweighted and weighted is too small.
LS0tDQp0aXRsZTogIldvbWVuIGluIFdvcmsgRm9yY2UiDQphdXRob3I6ICJLYW5naHVpIEppYW5nLCBFcmljYSBLaWxicmlkZSwgSGF5b3VuZyBLaW0sIFdhbnlpIFpoYW5nLCBhbmQgQ2F0aGVyaW5lIFpoYW8iDQpkYXRlOiAiU2VwdGVtYmVyIDIxIDIwMTYiDQpvdXRwdXQ6DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KI0JleW9uZCB0aGUgR2VuZGVyIFdhZ2UgR2FwDQoNCk11Y2ggYXR0ZW50aW9uLCBib3RoIGFjYWRlbWljYWxseSBhbmQgam91cm5hbGlzdGljYWxseSwgaGFzIGJlZW4gcGFpZCB0byB0aGUgIkdlbmRlciBXYWdlIEdhcCIgKGUuZy4gaHR0cDovL2luZXF1YWxpdHkuc3RhbmZvcmQuZWR1L19tZWRpYS9wZGYva2V5X2lzc3Vlcy9nZW5kZXJfcmVzZWFyY2gucGRmKS4gQXMgdGhpcyBpcyB3ZWxsLXRyZWQgdGVycml0b3J5LCBvdXIgdGVhbSBpcyBpbnRlcmVzdGVkIGluIGxvb2tpbmcgYmV5b25kIHRoZSBnZW5kZXIgd2FnZSBnYXAgYW5kIGFuYWx5emluZyB0aGUgaW50ZXItZ2VuZGVyIHdhZ2UgZ2FwLiBUaGF0IGlzLCB3aXRoaW4gd29tZW4gaW4gdGhlIHdvcmtmb3JjZSwgYXJlIHRoZXJlIGlkZW50aWZpYWJsZXMgZ2FwcyBpbiBlYXJuaW5ncz8gVGhlIGZvbGxvd2luZyByZXBvcnQgYm90aCBjb25maXJtcyBhIGdlbmRlciB3YWdlIGdhcCBhY3Jvc3Mgb2NjdXBhdGlvbnMgYW5kIGlkZW50aWZpZXMgZ2FwcyBhbW9uZyBzZXZlcmFsIGNoYXJhY3RlcmlzdGljcyBvZiB3b21lbiB3b3JraW5nIHdpdGhpbiBlYWNoIG9jY3VwYXRpb24uDQoNCiNXaGVyZSBpcyB0aGUgZ2FwPw0KDQpTaW5jZSB3ZSBrbm93IHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgd2FnZSBnYXAgYmV0d2VlbiBkaWZmZXJlbnQgcHJvZmVzc2lvbnMsIHdlIHVzZWQgb2NjdXBhdGlvbiBhcyBhIGNhdGVnb3J5IGZvciBvdXIgZGF0YS4gV2Ugc2VwZXJhdGVkIHRoZSBvY2N1cGF0aW9ucyBieSBncm91cHMuIFdpdGhpbiBlYWNoIGdyb3VwLCB3ZSBkaXZpZGVkIHRoZSBtZW4gYW5kIHdvbWVuIGFuZCBjb21wYXJlZCB0aGVpciB3ZWlnaHRlZCBtZWFuLg0KDQoNCldlIHN0YXJ0ZWQgYnkgaW1wb3J0aW5nIHRoZSBkYXRhIHNldCBmcm9tIHRoZSBVbml0ZWQgU3RhdGVzIENlbnN1cyBCdXJlYXUuDQpgYGB7ciBlY2hvPT1GQUxTRX0gDQojSW1wb3J0aW5nIERhdGEgU2V0DQojIHd3dzIuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL2Fjcy9kYXRhL3B1bXMvMjAxNC8xLVllYXIvY3N2X3B1cy56aXANCnNzMTRwdXNhID0gcmVhZC5jc3YoZmlsZS5jaG9vc2UoKSxoZWFkZXI9VFJVRSkgICMgcmVhZCBjc3YgZmlsZQ0Kc3MxNHB1c2IgPSByZWFkLmNzdihmaWxlLmNob29zZSgpLGhlYWRlcj1UUlVFKQ0KYGBgDQpGb3Igb3VyIGFuYXlsc2lzLCB3ZSB1c2VkIGRwbHlyLCBwbHlyLCBkcGx5ciwgcmNva2VoLCBnZ3Bsb3QyLCBwbG90bHksIGNhciwgc3VydmV5LCBhbmQgZ29vZ2xlVmlzLiAgDQpgYGB7ciBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojTGlicmFyaWVzDQpyZXF1aXJlKGRwbHlyKQ0KcmVxdWlyZShwbHlyKQ0KcmVxdWlyZShkcGx5cikNCnJlcXVpcmUocmJva2VoKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKGdvb2dsZVZpcykNCnJlcXVpcmUoY2FyKQ0KcmVxdWlyZShzdXJ2ZXkpDQpyZXF1aXJlKHJlYWRyKQ0KYGBgDQoNCmBgYHtyLCBldmFsID0gRkFMU0UsbWVzc2FnZT1GQUxTRSwgZWNobyA9IEZBTFNFfQ0KI0ltcG9ydGluZyBEYXRhIFNldCBpbiBhIGZhc3RlciB3YXkNCmxpYnJhcnkoZGF0YS50YWJsZSkNCnZhcmlhYmxlcz1jKCJTRVgiLCJPQ0NQIiwiV0tIUCIsIk1BUiIsIldBR1AiLCJTQ0hMIiwiRVNQIiwiUkFDMVAiLCJTVCIsIlBBT0MiLCJQV0dUUCIpDQpzczE0cHVzYT1mcmVhZCgiQzovVXNlcnMvdXNlci9EZXNrdG9wL1N0YXRpc3RpY3MvM3JkIHNlbWVzdGVyL0FEUy9Qcm9qZWN0MS9jc3ZfcHVzL3NzMTRwdXNhLmNzdiIsaGVhZD1UUlVFLHNlbGVjdD12YXJpYWJsZXMpDQpzczE0cHVzYj1mcmVhZCgiQzovVXNlcnMvdXNlci9EZXNrdG9wL1N0YXRpc3RpY3MvM3JkIHNlbWVzdGVyL0FEUy9Qcm9qZWN0MS9jc3ZfcHVzL3NzMTRwdXNiLmNzdiIsaGVhZD1UUlVFLHNlbGVjdD12YXJpYWJsZXMpDQpgYGANClRoZSBmb2xsb3dpbmcgc2hvd3MgdGhlIGNvbHVtbnMgd2UgaW1wb3J0ZWQuDQpgYGB7ciAsbWVzc2FnZT1GQUxTRX0NCmF0dGFjaChzczE0cHVzYSkNCiNuYW1lcyhzczE0cHVzYSkNCnNzMTRwdXNhX2VkaXQgPSBkYXRhLmZyYW1lKFNFWCxPQ0NQLFdLSFAsTUFSLFdBR1AsU0NITCxFU1AsIFJBQzFQLCBTVCwgUEFPQywgUFdHVFAsIEFHRVApDQpkZXRhY2goc3MxNHB1c2EpDQoNCmF0dGFjaChzczE0cHVzYikNCnNzMTRwdXNiX2VkaXQgPSBkYXRhLmZyYW1lKFNFWCxPQ0NQLFdLSFAsTUFSLFdBR1AsU0NITCxFU1AsIFJBQzFQLCBTVCwgUEFPQywgUFdHVFAsIEFHRVApDQpkZXRhY2goc3MxNHB1c2IpDQoNCkRhdGEgPSByYmluZChzczE0cHVzYV9lZGl0LHNzMTRwdXNiX2VkaXQpDQpjb2xuYW1lcyhEYXRhKSA8LSBjKCJHZW5kZXIiLCJPY2N1cGF0aW9uIiwgIldvcmtfaG91cnMiLCAiTWFycmlhZ2UiLCAiSW5jb21lIiwgIkVkdWNhdGlvbiIgLCJQYXJlbnRhbF9PY2N1cGF0aW9uIiwgIlJhY2UiLCAiU3RhdGUiLCAiQ2hpbGRyZW4iLCAiV2VpZ2h0IiwiQWdlIikNCg0KI3dyaXRlLmNzdihEYXRhLCBmaWxlID0gIkRhdGEuY3N2Iixyb3cubmFtZXM9VFJVRSkNCg0KI0RlbGV0ZSBpbmNvbWU9MC9OQSByb3dzDQpyb3dfdG9fa2VlcD13aGljaChEYXRhJEluY29tZT4wKQ0KRGF0YT1EYXRhW3Jvd190b19rZWVwLF0NCmBgYA0KV2UgcmVuYW1lZCBhbmQgY2F0ZWdvcml6ZWQgbXVsdGlwbGUgY2F0ZWdvcmllcyBmb3IgcmVhZGFibGlsdHkuDQoNCk5vdGU6IHdlIHVzZWQgZWlnaHQgaGlnaCBwYXlpbmcgb2NjdXBhdGlvbiB0byBjYXRlZ29yaXplIGpvYnMNCmBgYHtyLG1lc3NhZ2U9RkFMU0UsIGVycm9yPSBGQUxTRX0NCiNyZWNvZGUgT0NDUA0KY2xhc3MoRGF0YSRPY2N1cGF0aW9uKSA8LSAibnVtZXJpYyINCkRhdGEkT2NjdXBhdGlvbiA8LSBpZmVsc2UoRGF0YSRPY2N1cGF0aW9uID49IDEwICYgRGF0YSRPY2N1cGF0aW9uIDw9IDQzMCwgMSwgRGF0YSRPY2N1cGF0aW9uKQ0KRGF0YSRPY2N1cGF0aW9uIDwtIGlmZWxzZShEYXRhJE9jY3VwYXRpb24gPj0gMTAwNSAmIERhdGEkT2NjdXBhdGlvbiA8PSAxMjQwLCAyLCBEYXRhJE9jY3VwYXRpb24pDQpEYXRhJE9jY3VwYXRpb24gPC0gaWZlbHNlKERhdGEkT2NjdXBhdGlvbiA+PSA4MDAgJiBEYXRhJE9jY3VwYXRpb24gPD0gOTUwLCAzLCBEYXRhJE9jY3VwYXRpb24pDQpEYXRhJE9jY3VwYXRpb24gPC0gaWZlbHNlKERhdGEkT2NjdXBhdGlvbiA+PSAyMTA1ICYgRGF0YSRPY2N1cGF0aW9uIDw9IDIxNjAsIDQsIERhdGEkT2NjdXBhdGlvbikNCkRhdGEkT2NjdXBhdGlvbiA8LSBpZmVsc2UoRGF0YSRPY2N1cGF0aW9uID49IDMwMDAgJiBEYXRhJE9jY3VwYXRpb24gPD0gMzU0MCwgNSwgRGF0YSRPY2N1cGF0aW9uKQ0KRGF0YSRPY2N1cGF0aW9uIDwtIGlmZWxzZShEYXRhJE9jY3VwYXRpb24gPj0gNTEwICYgRGF0YSRPY2N1cGF0aW9uIDw9IDc0MCwgNiwgRGF0YSRPY2N1cGF0aW9uKQ0KRGF0YSRPY2N1cGF0aW9uIDwtIGlmZWxzZShEYXRhJE9jY3VwYXRpb24gPj0gMTMwMCAmIERhdGEkT2NjdXBhdGlvbiA8PSAxNTYwLCA3LCBEYXRhJE9jY3VwYXRpb24pDQpEYXRhJE9jY3VwYXRpb24gPC0gaWZlbHNlKERhdGEkT2NjdXBhdGlvbiA+PSAxNjAwICYgRGF0YSRPY2N1cGF0aW9uIDw9IDE5NjUsIDgsIERhdGEkT2NjdXBhdGlvbikNCg0Kcm93X3RvX2tlZXAyPXdoaWNoKERhdGEkT2NjdXBhdGlvbiVpbiUgYygxOjgpKQ0KRGF0YSA8LSBEYXRhW3Jvd190b19rZWVwMixdDQpEYXRhJE9jY3VwYXRpb24gPC0gYXMuZmFjdG9yKERhdGEkT2NjdXBhdGlvbikNCg0KbGV2ZWxzKERhdGEkT2NjdXBhdGlvbikgPC0gYygnTUdSJywgJ0NNTScsICdGSU4nLCAnTEdMJywgJ01FRCcgLCAnQlVTJywgJ0VORycsICdTQ0knKQ0KRGF0YSRSYWNlIDwtIGFzLmZhY3RvcihEYXRhJFJhY2UpDQpsZXZlbHMoRGF0YSRSYWNlKSA8LSBjKCdXaGl0ZScsICdCbGFjaycsICdBbWVyaWNhbiBJbmRpYW4nLCdBbGFza2EgTmF0aXZlJywnVHJpYmUgc3BlY2lmaWVkJywgJ0FzaWFuJyAsICdOYXRpdmUgSGF3YWlpYW4nLCAnT3RoZXInLCdUd28gb3IgbW9yZSByYWNlcycpDQoNCiNSZWNvZGUgUmVnaW9uDQojaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9yZWdpb25zX29mX3RoZV9Vbml0ZWRfU3RhdGVzIy9tZWRpYS9GaWxlOkNlbnN1c19SZWdpb25zX2FuZF9EaXZpc2lvbl9vZl90aGVfVW5pdGVkX1N0YXRlcy5zdmcNCg0KRGF0YSRSZWdpb24gPC0gcmVjb2RlKERhdGEkU3RhdGUsImMoMDksMjMsMjUsMzMsNDQsNTksMzQsMzYsNDIpPSdOb3J0aGVhc3QnO2MoMTcsMTgsMjYsMzgsNTUsMTksMjAsMjcsMjksMzEsMzgsNDYsMzkpPSdNaWR3ZXN0JzsgYygxMCwxMiwxMywyNCwzNyw0NSw1MSwxMSw1NCwwMSwyMSwyOCw0NywwNSwyMiw0MCw0OCk9J1NvdXRoJztjKDA0LDA4LDE2LDMwLDMyLDM1LDQ5LDUwLDAyLDA2LDE1LDQxLDUzLDU2KT0nV2VzdCc7JzcyJz0nUHVlcnRvIFJpY28nIikNCg0KIyBSZWNvZGUgRGl2aXNpb24NCkRhdGEkRGl2aXNpb24gPC0gcmVjb2RlKERhdGEkU3RhdGUsImMoNTMsNDEsNiwyLDE1KT0nUGFjaWZpYyc7Yyg0LDgsMTYsMzAsMzIsMzUsNDksNTYpPSdNb3VudGFpbic7IGMoMTksMjAsMjcsMjksMzEsMzgsNDYpPSdXZXN0IE5vcnRoIENlbnRyYWwnO2MoMTcsMTgsMjYsMzksNTUpPSdFYXN0IE5vcnRoIENlbnRyYWwnO2MoNSwyMiw0MCw0OCk9J1dlc3QgU291dGggQ2VudHJhbCc7YygxLDIxLDI4LDQ3KT0nRWFzdCBTb3V0aCBDZW50cmFsJztjKDM0LDM2LDQyKT0nTWlkZGxlIEF0bGFudGljJztjKDEwLDExLDEyLDEzLDI0LDM3LDQ1LDUxLDU0KT0nU291dGggQXRsYW50aWMnO2MoOSwyMywyNSwzMyw0NCw1MCk9J05ldyBFbmdsYW5kJyIpDQoNCiNSZWNvZGUgTWFycmlhZ2UNCkRhdGEkTWFycmlhZ2UgPC0gYXMuZmFjdG9yKERhdGEkTWFycmlhZ2UpDQpsZXZlbHMoRGF0YSRNYXJyaWFnZSkgPC0gYygiTWFycmllZCIsICJXaWRvd2VkIiwgIkRpdm9yY2VkIiwgIlNlcGVyYXRlZCIsICJOZXZlciBNYXJyaWVkIikNCg0KDQpjb2xuYW1lcyhEYXRhKSA8LSBjKCJHZW5kZXIiLCJPY2N1cGF0aW9uIiwgIldvcmtfaG91cnMiLCAiTWFycmlhZ2UiLCAiSW5jb21lIiwgIkVkdWNhdGlvbiIgLCJQYXJlbnRhbF9PY2N1cGF0aW9uIiwgIlJhY2UiLCAiU3RhdGUiLCAiQ2hpbGRyZW4iLCAiV2VpZ2h0IiwiQWdlIiwiUmVnaW9uIiwiRGl2aXNpb24iKQ0KIyBSZWNvZGUgRWR1Y2F0aW9uDQpEYXRhJEVkdWNhdGlvbiA8LSByZWNvZGUoRGF0YSRFZHVjYXRpb24sIjE6MTE9JzEnOzEyOjE5PScyJzsyMDoyMT0nMyc7MjI6MjM9JzQnOzI0PSc1JyIpDQpgYGANCkJhc2VkIG9uIHRoZSBlaWdodCBvY2N1cGF0aW9ucywgd2UgcGxvdCB0aGUgd2VpZ2h0ZWQgbWVhbiBvZiBtZW4gYW5kIHdvbWVuIHRvIGNvbXBhcmUgdGhlIGdhcC4NCmBgYHtyLCBlY2hvID0gRkFMU0V9DQojbWVkaWFuIHdhZ2UgZm9yIGVhY2ggb2NjdXBhdGlvbiBieSBnZW5kZXIgKGp1c3QgdG8gYWNrbm93bGVkZ2UgdGhhdCB0aGVyZSAqaXMqIGEgZ2VuZGVyIGdhcCkNCg0KRGF0YV9zZXhfb2NjcCA8LSBkZHBseShEYXRhLCAuKEdlbmRlciwgT2NjdXBhdGlvbiksIHN1bW1hcmlzZSwgTUVBTiA9IHdlaWdodGVkLm1lYW4oSW5jb21lLCBXZWlnaHQsIG5hLnJtID0gVCkpDQpnZ3Bsb3QoRGF0YV9zZXhfb2NjcCwgYWVzKHg9T2NjdXBhdGlvbiwgeT1NRUFOLCBmaWxsPWZhY3RvcihHZW5kZXIpKSkgKyANCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPSJkb2RnZSIpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlJkWWxHbiIpICsNCiAgbGFicyhmaWxsPSIiKSArIA0KICB5bGFiKCJNZWFuIFNhbGFyeSAoJCkiKSArIA0KICB4bGFiKCJPY2N1cGF0aW9ucyIpICsgDQogIGdndGl0bGUocGFzdGUoIlNhbGFyeSBDb21wYXJpc29uIGJldHdlZW4gTWVuICYgV29tZW4iKSkgKyANCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSwgDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd3aGl0ZScgKSkgKyANCiAgdGhlbWVfZ3JleShiYXNlX3NpemUgPSAxMikNCmBgYA0KDQpGcm9tIHRoZSBncmFwaCwgd2Ugc2VlIHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIG1lbiBhbmQgd29tZW4gb3ZlciBhbGwgb2NjdXBhdGlvbnMuIFRvIGdhaW4gYSBiZXR0ZXIgdW5kZXJzdGFuZGluZyB3ZSBncmFwaGVkIHRoZW0gYnkgcGVyY2VudGFnZSBmcm9tIHRoZSB3ZWlnaHRlZCBtZWFuIG9mIGJvdGggZ2VuZGVycy4NCmBgYHtyfQ0KRGF0YV9zZXhfb2NjcF9yYWNlIDwtIGRkcGx5KERhdGEsIC4oR2VuZGVyLCBPY2N1cGF0aW9uLCBSYWNlKSwgc3VtbWFyaXNlLCBNRUFOID0gd2VpZ2h0ZWQubWVhbihJbmNvbWUsIFdlaWdodCwgbmEucm0gPSBUKSkNCkRhdGFfc2V4X29jY3BfcmFjZV93b21lbiA8LSBEYXRhX3NleF9vY2NwX3JhY2Vbd2hpY2goRGF0YV9zZXhfb2NjcF9yYWNlJEdlbmRlciA9PSAyKSxdDQpEYXRhX3NleF9vY2NwX21lbiA8LSBEYXRhX3NleF9vY2NwW3doaWNoKERhdGFfc2V4X29jY3AkR2VuZGVyID09IDEpLF0NCkRhdGFfc2V4X29jY3Bfd29tZW4gPC0gRGF0YV9zZXhfb2NjcFt3aGljaChEYXRhX3NleF9vY2NwJEdlbmRlciA9PSAyKSxdDQoNCiNHZXR0aW5nIHRoZSBhdmVyYWdlIGZvciBib3RoIGdlbmRlcg0KRGF0YV9vY2N1IDwtIGRkcGx5KERhdGEsIC4oT2NjdXBhdGlvbiksc3VtbWFyaXNlLE1FQU4gPSB3ZWlnaHRlZC5tZWFuKEluY29tZSwgV2VpZ2h0LCBuYS5ybSA9IFQpKQ0KRGF0YV9zZXhfb2NjcF9tZWFuIDwtIGRhdGEuZnJhbWUoRGF0YV9zZXhfb2NjcF93b21lbiRPY2N1cGF0aW9uLERhdGFfc2V4X29jY3BfbWVuJE1FQU4sRGF0YV9zZXhfb2NjcF93b21lbiRNRUFOLCBEYXRhX29jY3UkTUVBTikNCmNvbG5hbWVzKERhdGFfc2V4X29jY3BfbWVhbikgPC0gYygnT2NjdXBhdGlvbicsJ01lbicsJ1dvbWVuJywnQXZlcmFnZScpDQoNCiNDaGFuZ2VzIGFsbCB0byBwZXJjZW50YWdlDQpEYXRhX3NleF9vY2NwX21lYW5fcGVyY2VudCA8LSBkYXRhLmZyYW1lKERhdGFfc2V4X29jY3Bfd29tZW4kT2NjdXBhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwKihEYXRhX3NleF9vY2NwX21lbiRNRUFOLURhdGFfb2NjdSRNRUFOKS9EYXRhX29jY3UkTUVBTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwKihEYXRhX3NleF9vY2NwX3dvbWVuJE1FQU4tRGF0YV9vY2N1JE1FQU4pL0RhdGFfb2NjdSRNRUFOKQ0KY29sbmFtZXMoRGF0YV9zZXhfb2NjcF9tZWFuX3BlcmNlbnQpIDwtIGMoJ09jY3VwYXRpb24nLCdNZW4nLCdXb21lbicpDQoNClBlcmNfc2V4IDwtIHBsb3RfbHkoRGF0YV9zZXhfb2NjcF9tZWFuX3BlcmNlbnQsIHggPSBXb21lbiwgeSA9IE9jY3VwYXRpb24sIG5hbWUgPSAiV29tZW4iLCBtb2RlID0gIm1hcmtlcnMiLCBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIpKSAlPiUNCiAgYWRkX3RyYWNlKHggPSBNZW4sIG5hbWUgPSAiTWVuIiwgeSA9IE9jY3VwYXRpb24sIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIpLCBtb2RlID0gIm1hcmtlcnMiKSAlPiUNCiAgbGF5b3V0KHRpdGxlID0gIkdlbmRlciBlYXJuaW5ncyBkaXNwYXJpdHkgYnkgUGVyY2VudGFnZSIseGF4aXMgPSBsaXN0KHRpdGxlID0gIlBlcmNlbnQgQ2hhbmdlICglKSIpLG1hcmdpbiA9IGxpc3QobCA9IDY1KSkNClBlcmNfc2V4DQpgYGANCk9iZXJzZXJ2YXRpb25zOg0KDQoxLiBNZWRpY2FsIG9jY3VwYXRpb25zIGhhcyB0aGUgbGFyZ2VzdCBkaXNwZXJpdHkgYmV0d2VlbiBtZW4gYW5kIHdvbWVuDQoNCjIuIFdvbWVuIGluIGxlZ2FsIG9jY3VwYXRpb25zIGFyZSB0aGUgY2xvc2VzdCB0byB0aGUgbWVkaWFuIA0KDQpJbiB0aGlzIHJlcG9ydCwgd2Ugd2lsbCBpbnZlc3RpZ2F0ZSA1IHByb2JhYmxlIGNhdXNlcyB0byBkZXRlcm1pbmUgd2hpY2ggZ3JvdXBzIG9mIHdvbWVuIHdpbGwgbW9zdCBsaWtlbHkgc3VjY2VlZCBvciBmYWlsLiBUaGVzZSBjYXRlZ29yaWVzIGFyZTogTWFycmlhZ2UgU3RhdHVzLCBNb3RoZXJob29kLCBMb2NhdGlvbiwgUmFjZSwgYW5kIEVkdWNhdGlvbi4gIA0KDQojRmFtaWxpYWwgUmVzcG9uc2liaWxpdGllcw0KDQpPdXIgbmV4dCB2YXJpYWJsZSBvZiBpbnRlcmVzdCBpcyB3b21lbidzIG1hcml0YWwgc3RhdHVzZXMuIEEgY29tbW9uIGV4cGxhbmF0aW9uIG9mIHRoZSBnZW5kZXIgd2FnZSBnYXAgaXMgdGhhdCB3b21lbiBtYWtlIHRoZSBkZWNpc2lvbiB3aXRoIHRoZWlyIGZhbWlsaWVzIHRvIHNoaWZ0IHRoZWlyIGZvY3VzIHRvIGhvdXNlaG9sZCByZXNwb25zaWJpbGl0aWVzLiBXZSdsbCBiZSBsb29raW5nIGF0IHRoZSBlZmZlY3Qgb2YgbWFycmlhZ2UgYW5kIG1vdGhlcmhvb2Qgc2VwZXJhdGVseSBmaXJzdCwgdGhlbiBsb29raW5nIGhvdyBtYXJpdGFsIHN0YXR1c2VzIG9mIG1vdGhlcnMgYWZmZWN0IHRoZWlyIGVhcm5pbmdzLg0KDQojI01hcml0YWwgU3RhdHVzDQpCZWxvdyB3ZSBhbmFseXNlIHRoZSBlZmZlY3Qgb2YgbWFyaXRhbCBzdGF0dXMgb24gbWVhbiBpbmNvbWUgZm9yIHdvbWVuIGFjcm9zcyBhbGwgb2NjdXBhdGlvbnMsIGFzIHdlbGwgYXMgd2l0aGluIG9jY3VwYXRpb25zLg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCg0KI21hcml0YWwgc3RhdHVzLCBzdWJzZXQgYXQgc3BlY2lmaWMgYWdlIHRvIGNvbnRyb2wgZm9yIGV4cGVyaWVuY2UNCkRhdGFfd29tZW4gPC0gZmlsdGVyKERhdGEsIEdlbmRlciA9PSAyKQ0KRGF0YV93ZWRfb2NjcCA8LSBkZHBseShEYXRhX3dvbWVuLCAuKE1hcnJpYWdlLCBPY2N1cGF0aW9uLCBBZ2UpLCBzdW1tYXJpc2UsIE1FQU4gPSB3ZWlnaHRlZC5tZWFuKEluY29tZSwgV2VpZ2h0LCBuYS5ybSA9IFQpKQ0KDQpwbG90KERhdGFfd2VkX29jY3AkQWdlLCBEYXRhX3dlZF9vY2NwJE1FQU4pDQoNCnN1bW1hcnkobG0oTUVBTiB+IE1hcnJpYWdlICsgQWdlICsgSShBZ2VeMikgLCBkYXRhID0gRGF0YV93ZWRfb2NjcCkpDQoNCiNGaW5hbmNlDQpXb21lbl9GSU48LWZpbHRlcihEYXRhX3dvbWVuLCBPY2N1cGF0aW9uID09IkZJTiIpDQpEYXRhX3dlZF9GSU4gPC0gZGRwbHkoV29tZW5fRklOLCAuKE1hcnJpYWdlLCBBZ2UpLCBzdW1tYXJpc2UsIE1FQU4gPSB3ZWlnaHRlZC5tZWFuKEluY29tZSwgV2VpZ2h0LCBuYS5ybSA9IFQpKQ0KDQpGSU4gPC0gcGxvdF9seShEYXRhX3dlZF9GSU4sIHggPSBBZ2UsIHkgPSBNRUFOLCBtb2RlID0gIm1hcmtlcnMiLCBvcGFjaXR5ID0gLjQsIGNvbG9yID0gTWFycmlhZ2UsIHRpdGxlID0gIldvbWVuIGluIEZpbmFuY2UiKSANCkZJTiA8LWFkZF90cmFjZShGSU4seSA9IGZpdHRlZChsb2VzcyhNRUFOIH4gQWdlICsgYXMubnVtZXJpYyhNYXJyaWFnZSkpKSAsIHggPSBBZ2UsIGNvbG9yID0gTWFycmlhZ2UpIA0KbGF5b3V0KEZJTiwgdGl0bGUgPSAiV29tZW4gaW4gRmluYW5jZSIpDQoNCnN1bW1hcnkobG0oTUVBTiB+IE1hcnJpYWdlICsgQWdlICsgSShBZ2VeMiksIGRhdGEgPSBEYXRhX3dlZF9GSU4pKQ0KDQojRW5naW5lZXJpbmcNCg0KV29tZW5fRU5HPC1maWx0ZXIoRGF0YV93b21lbiwgT2NjdXBhdGlvbiA9PSJFTkciKQ0KRGF0YV93ZWRfRU5HIDwtIGRkcGx5KFdvbWVuX0VORywgLihNYXJyaWFnZSwgQWdlKSwgc3VtbWFyaXNlLCBNRUFOID0gd2VpZ2h0ZWQubWVhbihJbmNvbWUsIFdlaWdodCwgbmEucm0gPSBUKSkNCg0KI3Bsb3RseQ0KRU5HIDwtIHBsb3RfbHkoRGF0YV93ZWRfRU5HLCB4ID0gQWdlLCB5ID0gTUVBTiwgbW9kZSA9ICJtYXJrZXJzIiwgb3BhY2l0eSA9IC40LCBjb2xvciA9IE1hcnJpYWdlLCB0aXRsZSA9ICJXb21lbiBpbiBGaW5hbmNlIikgDQpFTkcgPC1hZGRfdHJhY2UoRU5HLHkgPSBmaXR0ZWQobG9lc3MoTUVBTiB+IEFnZSArIGFzLm51bWVyaWMoTWFycmlhZ2UpKSkgLCB4ID0gQWdlLCBjb2xvciA9IE1hcnJpYWdlKSANCmxheW91dChFTkcsIHRpdGxlID0gIldvbWVuIGluIEVuZ2luZWVyaW5nIikNCg0KbG0xIDwtIGxtKE1FQU4gfiBNYXJyaWFnZSArIEFnZSArIEkoQWdlXjIpLCBkYXRhID0gRGF0YV93ZWRfRU5HKQ0Kc3VtbWFyeShsbTEpDQoNCiNNZWRpY2luZQ0KDQpXb21lbl9NRUQ8LWZpbHRlcihEYXRhX3dvbWVuLCBPY2N1cGF0aW9uID09Ik1FRCIpDQpEYXRhX3dlZF9NRUQgPC0gZGRwbHkoV29tZW5fTUVELCAuKE1hcnJpYWdlLCBBZ2UpLCBzdW1tYXJpc2UsIE1FQU4gPSB3ZWlnaHRlZC5tZWFuKEluY29tZSwgV2VpZ2h0LCBuYS5ybSA9IFQpKQ0KDQojcGxvdGx5DQpNRUQgPC0gcGxvdF9seShEYXRhX3dlZF9NRUQsIHggPSBBZ2UsIHkgPSBNRUFOLCBtb2RlID0gIm1hcmtlcnMiLCBvcGFjaXR5ID0gLjQsIGNvbG9yID0gTWFycmlhZ2UsIHRpdGxlID0gIldvbWVuIGluIEZpbmFuY2UiKSANCk1FRCA8LWFkZF90cmFjZShNRUQseSA9IGZpdHRlZChsb2VzcyhNRUFOIH4gQWdlICsgYXMubnVtZXJpYyhNYXJyaWFnZSkpKSAsIHggPSBBZ2UsIGNvbG9yID0gTWFycmlhZ2UpIA0KbGF5b3V0KE1FRCwgdGl0bGUgPSAiV29tZW4gaW4gRmluYW5jZSIpDQoNCg0Kc3VtbWFyeShsbShNRUFOIH4gTWFycmlhZ2UgKyBBZ2UgKyBJKEFnZV4yKSwgZGF0YSA9IERhdGFfd2VkX01FRCkpDQoNCiNTY2llbmNlDQoNCldvbWVuX1NDSTwtZmlsdGVyKERhdGFfd29tZW4sIE9jY3VwYXRpb24gPT0iU0NJIikNCkRhdGFfd2VkX1NDSSA8LSBkZHBseShXb21lbl9TQ0ksIC4oTWFycmlhZ2UsIEFnZSksIHN1bW1hcmlzZSwgTUVBTiA9IHdlaWdodGVkLm1lYW4oSW5jb21lLCBXZWlnaHQsIG5hLnJtID0gVCkpDQoNCiNwbG90bHkNClNDSSA8LSBwbG90X2x5KERhdGFfd2VkX1NDSSwgeCA9IEFnZSwgeSA9IE1FQU4sIG1vZGUgPSAibWFya2VycyIsIG9wYWNpdHkgPSAuNCwgY29sb3IgPSBNYXJyaWFnZSwgdGl0bGUgPSAiV29tZW4gaW4gU2NpZW5jZSIpIA0KU0NJIDwtYWRkX3RyYWNlKFNDSSx5ID0gZml0dGVkKGxvZXNzKE1FQU4gfiBBZ2UgKyBhcy5udW1lcmljKE1hcnJpYWdlKSkpICwgeCA9IEFnZSwgY29sb3IgPSBNYXJyaWFnZSkgDQpsYXlvdXQoU0NJLCB0aXRsZSA9ICJXb21lbiBpbiBTY2llbmNlIikNCg0KDQpzdW1tYXJ5KGxtKE1FQU4gfiBNYXJyaWFnZSArIEFnZSArIEkoQWdlXjIpLCBkYXRhID0gRGF0YV93ZWRfU0NJKSkNCg0KI01hbmFnZXJzDQpXb21lbl9NR1I8LWZpbHRlcihEYXRhX3dvbWVuLCBPY2N1cGF0aW9uID09Ik1HUiIpDQpEYXRhX3dlZF9NR1IgPC0gZGRwbHkoV29tZW5fTUdSLCAuKE1hcnJpYWdlLCBBZ2UpLCBzdW1tYXJpc2UsIE1FQU4gPSB3ZWlnaHRlZC5tZWFuKEluY29tZSwgV2VpZ2h0LCBuYS5ybSA9IFQpKQ0KDQpNR1IgPC0gcGxvdF9seShEYXRhX3dlZF9NR1IsIHggPSBBZ2UsIHkgPSBNRUFOLCBtb2RlID0gIm1hcmtlcnMiLCBvcGFjaXR5ID0gLjQsIGNvbG9yID0gTWFycmlhZ2UsIHRpdGxlID0gIldvbWVuIGluIE1hbmFnZW1lbnQiKSANCk1HUiA8LWFkZF90cmFjZShNR1IseSA9IGZpdHRlZChsb2VzcyhNRUFOIH4gQWdlICsgYXMubnVtZXJpYyhNYXJyaWFnZSkpKSAsIHggPSBBZ2UsIGNvbG9yID0gTWFycmlhZ2UpIA0KbGF5b3V0KE1HUiwgdGl0bGUgPSAiV29tZW4gaW4gTWFuYWdlbWVudCIpDQoNCnN1bW1hcnkobG0oTUVBTiB+IE1hcnJpYWdlICsgQWdlICsgSShBZ2VeMiksIGRhdGEgPSBEYXRhX3dlZF9NR1IpKQ0KDQoNCiNMYXd5ZXJzDQpXb21lbl9MR0w8LWZpbHRlcihEYXRhX3dvbWVuLCBPY2N1cGF0aW9uID09IkxHTCIpDQpEYXRhX3dlZF9MR0wgPC0gZGRwbHkoV29tZW5fTEdMLCAuKE1hcnJpYWdlLCBBZ2UpLCBzdW1tYXJpc2UsIE1FQU4gPSB3ZWlnaHRlZC5tZWFuKEluY29tZSwgV2VpZ2h0LCBuYS5ybSA9IFQpKQ0KDQpMR0wgPC0gcGxvdF9seShEYXRhX3dlZF9MR0wsIHggPSBBZ2UsIHkgPSBNRUFOLCBtb2RlID0gIm1hcmtlcnMiLCBvcGFjaXR5ID0gLjQsIGNvbG9yID0gTWFycmlhZ2UpIA0KTEdMIDwtYWRkX3RyYWNlKExHTCx5ID0gZml0dGVkKGxvZXNzKE1FQU4gfiBBZ2UgKyBhcy5udW1lcmljKE1hcnJpYWdlKSkpICwgeCA9IEFnZSwgY29sb3IgPSBNYXJyaWFnZSkgDQpsYXlvdXQoTEdMLCB0aXRsZSA9ICJXb21lbiBpbiBMYXciKQ0KDQpzdW1tYXJ5KGxtKE1FQU4gfiBNYXJyaWFnZSArIEFnZSArIEkoQWdlXjIpLCBkYXRhID0gRGF0YV93ZWRfTEdMKSkNCg0KDQojQnVzaW5lc3MNCg0KV29tZW5fQlVTPC1maWx0ZXIoRGF0YV93b21lbiwgT2NjdXBhdGlvbiA9PSJCVVMiKQ0KRGF0YV93ZWRfQlVTIDwtIGRkcGx5KFdvbWVuX0JVUywgLihNYXJyaWFnZSwgQWdlKSwgc3VtbWFyaXNlLCBNRUFOID0gd2VpZ2h0ZWQubWVhbihJbmNvbWUsIFdlaWdodCwgbmEucm0gPSBUKSkNCg0KQlVTIDwtIHBsb3RfbHkoRGF0YV93ZWRfQlVTLCB4ID0gQWdlLCB5ID0gTUVBTiwgbW9kZSA9ICJtYXJrZXJzIiwgb3BhY2l0eSA9IC40LCBjb2xvciA9IE1hcnJpYWdlKSANCkJVUyA8LWFkZF90cmFjZShCVVMseSA9IGZpdHRlZChsb2VzcyhNRUFOIH4gQWdlICsgYXMubnVtZXJpYyhNYXJyaWFnZSkpKSAsIHggPSBBZ2UsIGNvbG9yID0gTWFycmlhZ2UpIA0KbGF5b3V0KEJVUywgdGl0bGUgPSAiV29tZW4gaW4gQnVzaW5lc3MiKQ0KDQpzdW1tYXJ5KGxtKE1FQU4gfiBNYXJyaWFnZSArIEFnZSArIEkoQWdlXjIpLCBkYXRhID0gRGF0YV93ZWRfQlVTKSkNCg0KI0NvbXB1dGVyDQoNCldvbWVuX0NNTTwtZmlsdGVyKERhdGFfd29tZW4sIE9jY3VwYXRpb24gPT0iQ01NIikNCkRhdGFfd2VkX0NNTSA8LSBkZHBseShXb21lbl9DTU0sIC4oTWFycmlhZ2UsIEFnZSksIHN1bW1hcmlzZSwgTUVBTiA9IHdlaWdodGVkLm1lYW4oSW5jb21lLCBXZWlnaHQsIG5hLnJtID0gVCkpDQoNCkNNTSA8LSBwbG90X2x5KERhdGFfd2VkX0NNTSwgeCA9IEFnZSwgeSA9IE1FQU4sIG1vZGUgPSAibWFya2VycyIsIG9wYWNpdHkgPSAuNCwgY29sb3IgPSBNYXJyaWFnZSkgDQpDTU0gPC1hZGRfdHJhY2UoQ01NLHkgPSBmaXR0ZWQobG9lc3MoTUVBTiB+IEFnZSArIGFzLm51bWVyaWMoTWFycmlhZ2UpKSkgLCB4ID0gQWdlLCBjb2xvciA9IE1hcnJpYWdlKSANCmxheW91dChDTU0sIHRpdGxlID0gIldvbWVuIGluIExhdyIpDQoNCnN1bW1hcnkobG0oTUVBTiB+IE1hcnJpYWdlICsgQWdlICsgSShBZ2VeMiksIGRhdGEgPSBEYXRhX3dlZF9DTU0pKQ0KDQpgYGAgDQpPYnNlcnZhdGlvbnM6DQoNCjEuIE92ZXJhbGwsd2lkb3dlZCBhbmQgc2VwZXJhdGVkIHdvbWVuIG1ha2Ugc2lnbmlmaWNhbnRseSBsZXNzIHRoYW4gbWFycmllZCB3b21lbiB3aGVuIG9jY3VwYXRpb25zIGFyZSBwb29sZWQuDQoNCjIuIE1hcml0YWwgc3RhdHVzIGhhcyBubyBlZmZlY3Qgb24gZWFybmluZyBmb3Igd29tZW4gaW4gdGhlIHNjaWVudGlmaWMgZmllbGQNCg0KMy4gSW50ZXJlc3RpbmdseSwgZm9yIG1vc3Qgb2NjdXBhdGlvbnMgd2hlcmUgbWFyaXRhbCBzdGF0dXMgaXMgc2lnbmlmaWNhbnQsIHdvbWVuIGluIHRoZWlyIHByb2Zlc3Npb24gd2hvIGhhdmUgbmV2ZXIgYmVlbiBtYXJyaWVkIGVhcm4gbW9yZSB0aGFuIG1hcnJpZWQgd29tZW4sIHdoZXJlYXMgd2lkb3dlZCBhbmQgc2VwZXJhdGVkIHdvbWVuIGVhcm4gc2lnbmlmaWNhbnRseSBsZXNzLiBQZXJoYXBzIHdpZG93ZWQgb3Igc2VwZXJhdGVkIHdvbWVuIGFyZSBtb3JlIGxpa2VseSB0byBoYXZlIGNoaWxkcmVuIHRoYW4gbmV2ZXIgbWFycmllZCB3b21lbiwgYW5kIHRodXMgbXVzdCBzaG91bGRlciBtb3JlIHJlc3BvbnNpYmlsaXRpZXMgb3V0c2lkZSBvZiB3b3JrLg0KIA0KDQojTW90aGVyaG9vZA0KDQpBZnRlciBpbnZlc3RpZ2F0aW5nIGhvdyBtYXJyaWFnZSBzdGF0dXMgYWZmZWN0IHdvbWVuJ3MgaW5jb21lLCB3ZSBsb29rZWQgaW50byB0aGUgcHJlc2VuY2UgYW5kIGFnZSBvZiBjaGlsZHJlbiBvd25lZCBieSB0aGUgd29tZW4gdG8gZGV0ZXJtaW5lIGhvdyBpdCBtaWdodCBjb3JyZWxhdGUgdG8gd29tZW4ncyBpbmNvbWUuIFdlIGV4cGVjdCB3b21lbiB3aXRoIENoaWxkcmVuIHVuZGVyIDYgbWF5IGhhdmUgbGVzcyB3b3JraW5nIGhvdXJzIGFuZCB0aHVzIGxvd2VyIGluY29tZSAocmVhc29uaW5nOiB3aGVuIGEgY2hpbGQgaXMgeW91bmcgdGhlIHdvbWVuIG9mIHRoZSBob3VzZSBpcyBtb3JlIGxpa2VseSB0byBzdGF5IGhvbWUgd2l0aCB0aGVpciBjaGlsZHJlbi4gQXMgd2Ugc2VlIHRoZSBjaGlsZHJlbiBncm93LCB3ZSBleHBlY3QgYSB0cmVuZCBmb3Igd29tZW4gdG8gZWFybiB0aGUgaGlnaGVyLikgRnVydGhlcm1vcmUsIHdlIG1heSBhbHNvIHdhbnQgdG8gZmlndXJlIG91dCBob3cgb2NjdXBhdGlvbiBhbmQgYWdlIGZvciB3b21lbiB3aXRoIGNoaWxkcmVuIGFmZmVjdCB0aGVpciBpbmNvbWUuICANCg0KQXQgZmlyc3QsIHdlIHdhbnQgdG8gaGF2ZSBhIGdsYW5jZSBhdCB0aGUgaW5jb21lIGxldmVsIG9mIHRoZSBkaWZmZXJlbnQgZ3JvdXBzIG9mIGZlbWFsZXMuIEJhc2ljYWxseSBmZW1hbGVzIGFyZSBkaXZpZGVkIGludG8gZm91ciBjYXRlZ29yaWVzIHJlZ2FyZGluZyB0aGUgcHJlc2VuY2UgYW5kIGFnZSBvZiBDaGlsZHJlbjogRmVtYWxlcyB3aXRoIENoaWxkcmVuIHVuZGVyIDYsIEZlbWFsZXMgd2l0aCBDaGlsZHJlbiBmcm9tIDYgdG8gMTcsIEZlbWFsZXMgd2l0aCBDaGlsZHJlbiB1bmRlciA2IGFuZCBhYm92ZSA2LCBGZW1hbGVzIHdpdGggTm8gQ2hpbGRyZW4uIFRodXMgd2Ugc2ltcGx5IGNyZWF0IGEgYmFyIGNoYXJ0IHRvIGlsbHVzdHJhdGUgdGhlIGluY29tZSBkaWZmZXJlbmNlLg0KYGBge3J9DQpEYXRhX3dvbWVuIDwtIGZpbHRlcihEYXRhLCBHZW5kZXIgPT0gMikNCkRhdGFfd29tZW4kQWdlZ3JvdXAgPC0gY3V0KGFzLm51bWVyaWMoRGF0YV93b21lbiRBZ2UpLCBicmVha3MgPSBjKDIwLDI1LDMwLDM1LDQwLDQ1LDUwLDU1LDYwLDY1KSkNCkRhdGFfd29tZW4gPC0gZmlsdGVyKERhdGFfd29tZW4sIEFnZSA+IDIwICYgQWdlIDwgNjYpDQoNCg0KDQojIyMgTGluZSBDaGFydCB3aXRoIHJlZ2FyZCB0byBBZ2UNCg0KTW90aGVySG9vZD1zZWxlY3QoRGF0YV93b21lbiwgSW5jb21lLENoaWxkcmVuLEFnZWdyb3VwKQ0KZGV0YWNoKHBhY2thZ2U6cGx5cikNCkdyb3VwZWRNb3RoZXJIb29kIDwtDQogTW90aGVySG9vZCAlPiUNCiBuYS5vbWl0KCkgJT4lDQogZ3JvdXBfYnkoQ2hpbGRyZW4sQWdlZ3JvdXApICU+JQ0KIHN1bW1hcml6ZSgNCiAgIEF2Z0luY29tZSA9IG1lYW4oSW5jb21lKQ0KICkNCg0KR3JvdXBlZE1vdGhlckhvb2QkQ2hpbGRyZW48LWZhY3RvcihHcm91cGVkTW90aGVySG9vZCRDaGlsZHJlbiwgbGV2ZWxzID0gYygiMSIsIjIiLCIzIiwiNCIpLCBjKCdDaGlsZHJlbiB1bmRlciA2JywnQ2hpbGRyZW4gZnJvbSA2IHRvIDE3JywnQ2hpbGRyZW4gdW5kZXIgNiBhbmQgYWJvdmUgNicsJ05vIENoaWxkcmVuJykpDQoNCmBgYA0KDQpPYnNlcnZhdGlvbnM6DQoNCjEuV29tZW4gd2l0aCBjaGlsZHJlbiA2IHRvIDE3IGhhcyBvYnZpb3VzbHkgaGlnaGVyIEF2ZXJhZ2UgSW5jb21lIGFzIHRoZXkgaGF2ZSBtb3JlIHdvcmtpbmcgZXhwZXJpZW5jZSBhbmQgZG8gbm90IG5lZWQgdG8gc3BlbmQgdG9vIG11Y2ggdGltZSB0byB0YWtlIGNhcmUgb2YgeW91bmcgY2hpbGRyZW4uIA0KDQoyLldvbWVuIHdpdGggQ2hpbGRyZW4gb2YgYm90aCBhZ2VzIGhhdmUgc2xpZ2h0bHkgbG93ZXIgaW5jb21lLCB3aGljaCBpcyBhbHNvIHJlYXNvbmFibGUgYXMgdGhleSBtYXkgbm90IGhhdmUgdG9vIG11Y2ggdGltZSBpbiB3b3JrLg0KDQoNClRoZSBiYXIgY2hhcnQgdmVyaWZpZXMgb3VyIGd1ZXNzLiBOZXh0LCBpbiBvcmRlciB0byBiZXR0ZXIgdW5kZXJzdGFuZCB3aHkgd29tZW4gd2l0aCBjaGlsZHJlbiA2IHRvIDE3IGhhdmUgaGlnaGVyIGluY29tZSBhbmQgd2hldGhlciBpdCBoYXMgYW55dGhpbmcgdG8gZG8gd2l0aCBhZ2UsIHdlIGFyZSBnb2luZyB0byBzdHVkeSBob3cgdGhlIGluY29tZSBjaGFuZ2UgZm9yIGRpZmZlcmVudCBncm91cHMgb2Ygd29tZW4gdGhyb3VnaCBvdXQgYWdlLiBCYXNpY2FsbHkgd2UgdHJ5IHRvIGFuYWx5emUgYnkgbGluZSBjaGFydCB0byBzZWUgdGhlIGluY29tZSB0cmVuZCBhbmQgY29tcGFyZS4gDQpgYGB7cn0NCg0KI2dncGxvdChHcm91cGVkTW90aGVySG9vZCwgYWVzKHg9QWdlZ3JvdXAsIHk9QXZnSW5jb21lLGZpbGw9Q2hpbGRyZW4pKSArDQojICBnZW9tX2Jhcih3aWR0aD0uNSwgc3RhdD0iaWRlbnRpdHkiKSsNCiMgIHhsYWIoIkFnZSBHcm91cCIpICsgeWxhYigiTWVhbiBJbmNvbWUiKSArDQojICBnZ3RpdGxlKCJJbmNvbWUgZm9yIE1vdGhlcmhvb2QiKQ0KDQoNCmdncGxvdChHcm91cGVkTW90aGVySG9vZCwgYWVzKHg9QWdlZ3JvdXAsIHk9QXZnSW5jb21lLGdyb3VwPUNoaWxkcmVuLGNvbG91cj1DaGlsZHJlbikpICsNCiBnZW9tX2xpbmUoKSsNCiBnZW9tX3BvaW50KCkrDQogI2d1aWRlcyhmaWxsPUZBTFNFKSArDQogeGxhYigiQWdlIEdyb3VwIikgKyB5bGFiKCJNZWFuIEluY29tZSIpICsNCiBnZ3RpdGxlKCJJbmNvbWUgZm9yIE1vdGhlcmhvb2QiKQ0KDQpgYGANCk9ic2VydmF0aW9uczoNCg0KMS4gQmVmb3JlIDQ1LTUwIHllYXJzIG9sZCwgdGhlcmUgaXMgYW4gYWJ2aW91cyBpbmNyZWFzaW5nIHRyZW5kIG9mIGluY29tZSBiYXNpY2FsbHkgZm9yIGFsbCBncm91cHMuIEFuZCBhZnRlciB0aGF0IGFnZSwgYXZlcmFnZSBpbmNvbWUgYmVnaW5zIHRvIGRlY3JlYXNlIG9yIHN0YWJsaXplLg0KDQoyLiBTdXJwcmlzaW5nbHksIGZvciB0aGUgc2FtZSBhZ2UgZ3JvdXAsIHdvbWVuIHdpdGggQ2hpbGRyZW4gdW5kZXIgNiBoYXZlIGhpZ2hlciBpbmNvbWUuIFdoaWxlIHdvbWVuIHdpdGggY2hpbGRyZW4gZnJvbSA2IGFuZCAxNyBoYXZlIGhpZ2hlciBpbmNvbWUgYWZ0ZXIgNDUgeWVhcnMgb2xkLCB3aGljaCBtaWdodCBiZSB0aGUgcmVhc29uIHRoaXMgZ3JvdXAgaGFzIGhpZ2hlciBhdmVyYWdlIGluY29tZS4gT24gdGhlIG90aGVyIGhhbmQsIHdvbWVuIHdpdGggbm8gY2hpbGRyZW4gZG9lc24ndCBlYXJuIGxlc3MgdGhhbiBvdGhlciBncm91cHMgYXQgeW91bmdlciBhZ2UgZ3JvdXBzLCBidXQgdGhlaXIgaW5jb21lIGJlY29tZSBzdGFibGUgYW5kIGxlc3MgdGhhbiBvdGhlcnMgYWZ0ZXIgNDAgeWVhcnMgb2xkLiANCg0KDQpOZXh0LCB3ZSB3YW50ZWQgdG8gc2VlIGhvdyB0aGUgd29ya2luZyBob3VycyByZWxhdGVkIHRvIHRoZSBpbmNvbWUgb2Ygd29tZW4gaW4gZGlmZmVyZW50IGdyb3VwLiBXaWxsIHdvbWVuIHdpdGggY2hpbGRyZW4gZnJvbSA2IHRvIDE3IGhhdmUgbW9yZSB3b3JraW5nIGhvdXJzIGFuZCBnZW5lcmF0ZSBoaWdoZXIgaW5jb21lPyBUaHVzIHdlIHdhbnQgdG8gdXNlIGJ1YmJsZSBjaGFydCB0byBpbnRlZ3JhdGUgd29ya2luZyBob3VycywgYXZlcmFnZSBpbmNvbWUsIHRoZSBncm91cCBjb3VudCBpbiBhIGJ1YmJsZSBjaGFydCBzbyB0aGF0IGFsbCB0aGUgaW5mb3JtYXRpb24gY2FuIGJlIGdhaW5lZCBpbiB0aGUgc2FtZSBncmFwaC4gDQpgYGB7cn0NCk1vdGhlcldvcmtpbmc9c2VsZWN0KERhdGFfd29tZW4sIEluY29tZSxDaGlsZHJlbixXb3JrX2hvdXJzKQ0KI2RldGFjaChwYWNrYWdlOnBseXIpDQpHcm91cGVkTW90aGVyV29ya2luZyA8LQ0KICBNb3RoZXJXb3JraW5nICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIGdyb3VwX2J5KENoaWxkcmVuLFdvcmtfaG91cnMpICU+JSANCiAgc3VtbWFyaXplKEF2Z0luY29tZSA9IG1lYW4oSW5jb21lKSwgY291bnQ9bigpKSANCg0KR3JvdXBlZE1vdGhlcldvcmtpbmckQ2hpbGRyZW48LWZhY3RvcihHcm91cGVkTW90aGVyV29ya2luZyRDaGlsZHJlbiwgbGV2ZWxzID0gYygiMSIsIjIiLCIzIiwiNCIpLGxhYmVscz0gYygnQ2hpbGRyZW4gdW5kZXIgNicsJ0NoaWxkcmVuIGZyb20gNiB0byAxNycsJ0NoaWxkcmVuIHVuZGVyIDYgYW5kIGFib3ZlIDYnLCdObyBDaGlsZHJlbicpKQ0KDQojIG5vdGUgaG93IHNpemUgaXMgYXV0b21hdGljYWxseSBzY2FsZWQgYW5kIGFkZGVkIGFzIGhvdmVyIHRleHQNCnBsb3RfbHkoR3JvdXBlZE1vdGhlcldvcmtpbmcsIHggPSBXb3JrX2hvdXJzLCB5ID0gQXZnSW5jb21lLHNpemU9c3FydChjb3VudCksIGNvbG9yID0gQ2hpbGRyZW4sbW9kZSA9ICJtYXJrZXJzIixob3ZlcmluZm8gPSAidGV4dCIsdGV4dCA9IHBhc3RlKCJBdmdJbmNvbWU6IixBdmdJbmNvbWUsIjxicj4iLCJDb3VudDoiLGNvdW50LCI8YnI+IikpDQpgYGANCg0KT2JzZXJ2YXRpb25zOg0KDQoxLiBXaGVuIHdvcmtfaG91cnMgc21hbGxlciB0aGFuIDYwSHJzLCBBdmcgSW5jb21lIHRlbmQgdG8gYmUgcG9zaXRpdmVseSByZWxhdGVkIHRvIHdvcmsgaG91ciwgd2hpY2ggYWdyZWVzIHdpdGggb3VyIGNvbW1vbiBrbm93bGVkZ2UuIE1vc3Qgd29tZW4gY29uY2VudHJhdGUgYXJvdW5kIDQwIHdvcmtpbmcgaG91cnMuDQoNCjIuIFRoZXJlIGFyZSBnZW5lcmFsbHkgbW9yZSBmZW1hbGVzIHdpdGggbm8gQ2hpbGRyZW4gaW4gdGhpcyBzdXJ2ZXkgYXMgZ3JlZW4gY2lyY2xlcyBhcmUgZ2VuZXJhbGx5IGxhcmdlciBpbiBzaXplLiBBbHNvIGl0IGNhbiBiZSBvYnNlcnZlZCB0aGVyZSBhcmUgbXVjaCBtb3JlIHdvbWVuIHdpdGggbm8gY2hpbGRyZW4gd29ya2luZyBtb3JlIHRoYW4gNTAgaG91cnMgY29tcGFyZWQgdG8gb3RoZXIgZ3JvdXBzLiBPbiB0aGUgb3RoZXIgaGFuZCwgdGhlcmUgYXJlIGJhc2ljYWxseSBsZXNzIHdvbWVuIHdpdGggY2hpbGRyZW4gZnJvbSBib3RoIGFnZSBncm91cHMuDQoNCjMuIEZlbWFsZXMgd2l0aCBDaGlsZHJlbiBmcm9tIDYgdG8gMTcgb2Z0ZW4gaGF2ZSBoaWdoZXIgYXZnIGluY29tZS4gV2hpbGUgZm9yIHRoZSBzYW1lIHdvcmtpbmcgaG91ciBsZXZlbCwgZmVtYWxlcyB3aXRoIG5vIGNoaWxkcmVuIGFyZSBmcmVxdWVudGx5IGhhdmUgbG93ZXIgYXZlcmFnZSBpbmNvbWUuDQoNCg0KTmV4dCB3ZSB3YW50IHRvIGludmVzdGlnYXRlIHdoZXRoZXIgdGhlIGluY29tZSBkaWZmZXJlbmNlIGFtb25nIGZvdXIgZ3JvdW9wcyBvZiBmZW1hbGUgaGF2ZSBhbnkgcmVsYXRpb25zaGlwIHRvIHRoZWlyIG9jY3VwYXRpb24uIFRoZXJlZm9yZSB3ZSB1c2UgdGhpcyBjaGFydCB0byBjb21wYXJlIHRoZSBpbmNvbWUgZm9yIGZvdXIgZ3JvdXBzIG9mIHdvbWVuIGluIGRpZmZlcmVudCBvY2N1cGF0aW9ucy4gQmFzaWNhbGx5LCBkYXJrZXIgY29sb3IgcmVwcmVzZW50IGhpZ2hlciBpbmNvbWUgYW5kIGxhcmdlciBzaXplIGluZGljYXRlIGxhcmdlciBncm91cCBzaXplLg0KYGBge3J9DQpNb3RoZXJPY2N1cGF0aW9uPXNlbGVjdChEYXRhX3dvbWVuX2FnZSwgSW5jb21lLENoaWxkcmVuLE9jY3VwYXRpb24pDQoNCkdyb3VwZWRNb3RoZXJPY2N1cGF0aW9uIDwtDQogIE1vdGhlck9jY3VwYXRpb24gJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgZ3JvdXBfYnkoQ2hpbGRyZW4sT2NjdXBhdGlvbikgJT4lIA0KICBzdW1tYXJpemUoDQogICAgQXZnSW5jb21lID0gbWVhbihJbmNvbWUpLA0KICAgIGNvdW50PW4oKQ0KICApIA0KDQpnZ3Bsb3QoR3JvdXBlZE1vdGhlck9jY3VwYXRpb24sYWVzKHg9YXMuZmFjdG9yKENoaWxkcmVuKSkpK2dlb21fcG9pbnQoYWVzKHk9T2NjdXBhdGlvbixzaXplPWNvdW50LGNvbG91cj1BdmdJbmNvbWUpKStnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoQXZnSW5jb21lKSx5PU9jY3VwYXRpb24sb3BhY2l0eT0wKSxoanVzdD0wLCB2anVzdD0xLHNpemU9Mi41KSArc2NhbGVfY29sb3VyX2dyYWRpZW50KGxvdz0id2hpdGUiLGhpZ2g9InJlZCIpICtzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz1jKCJDaGlsZHJlbiB1bmRlciA2IiwgIkNoaWxkcmVuIGZyb20gNiB0byAxNyIsICJDaGlsZHJlbiAjdW5kZXIgNiBhbmQgYWJvdmUgNiIsICJObyBDaGlsZHJlbiIpKQ0KYGBgDQojTWFyaXRhbCBzdGF0dXNlcyBvZiBtb3RoZXJzDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQpNb3RoZXJNYXJpdGFsT2NjdXBhdGlvbj1zZWxlY3QoRGF0YV93b21lbiwgSW5jb21lLENoaWxkcmVuLE9jY3VwYXRpb24sIE1hcnJpYWdlLCBBZ2UpDQpNb3RoZXJNYXJpdGFsT2NjdXBhdGlvbiA8LSBuYS5vbWl0KE1vdGhlck1hcml0YWxPY2N1cGF0aW9uKQ0KTW90aGVyTWFyaXRhbE9jY3VwYXRpb24kQ2hpbGRyZW4gPC0gaWZlbHNlKE1vdGhlck1hcml0YWxPY2N1cGF0aW9uJENoaWxkcmVuID09IDQsIDAsIDEpDQojZGV0YWNoKHBhY2thZ2U6cGx5cikNCkdyb3VwZWRNb3RoZXJNYXJpdGFsT2NjdXBhdGlvbiA8LQ0KICBNb3RoZXJNYXJpdGFsT2NjdXBhdGlvbiAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBncm91cF9ieShDaGlsZHJlbixPY2N1cGF0aW9uLCBNYXJyaWFnZSwgQWdlKSAlPiUgDQogIHN1bW1hcml6ZSgNCiAgICBBdmdJbmNvbWUgPSBtZWFuKEluY29tZSksDQogICAgY291bnQ9bigpDQogICkgDQoNCkdyb3VwZWRNb3RoZXJNYXJpdGFsIDwtDQogIE1vdGhlck1hcml0YWxPY2N1cGF0aW9uICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIGdyb3VwX2J5KENoaWxkcmVuLCBNYXJyaWFnZSwgQWdlKSAlPiUgDQogIHN1bW1hcml6ZSgNCiAgICBBdmdJbmNvbWUgPSBtZWFuKEluY29tZSksDQogICAgY291bnQ9bigpDQogICkgDQoNCg0KZ2dwbG90KEdyb3VwZWRNb3RoZXJNYXJpdGFsLGFlcyh5ID0gQXZnSW5jb21lLCB4ID1BZ2UsY29sb3VyPWFzLmZhY3RvcihDaGlsZHJlbikpKSArDQpnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgZmlsbD1OQSkgKyBmYWNldF93cmFwKH5NYXJyaWFnZSwgc2NhbGVzPSAiZnJlZSIpDQpzdW1tYXJ5KGxtKEF2Z0luY29tZSB+IEFnZSArIEkoQWdlXjIpICsgQ2hpbGRyZW4qTWFycmlhZ2UsIGRhdGEgPSBHcm91cGVkTW90aGVyTWFyaXRhbE9jY3VwYXRpb24pKQ0KYGBgDQoNCk9ic2VydmF0aW9uczogV2UgY2FuIHNlZSBpbiB0aGUgc3VtbWFyeSByZXN1bHRzIG9mIHRoZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIG1hcml0YWwgc3RhdHVzIGFuZCBtb3RoZXJob29kLCBzaW5nbGUgbW90aGVycyBlYXJuIHNpZ25pZmljYW50bHkgbGVzcyB3aGVuIG9jY3VwYXRpb25zIGFyZSBwb29sZWQgYW5kIGFnZSBpcyBjb250cm9sbGVkLg0KDQojRWR1Y2F0aW9uDQoNCldlIGV4cGVjdCB0aGF0IGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQgd291bGQgYWZmZWN0IHRoZSB3b21lbidzIGluY29tZS4gV2UgbWF5IHdhbnQgdG8gZmlndXJlIG91dCB3aGljaCBkZWdyZWUgaXMgdGhlIG1vc3QgaW1wb3J0YW50IGZhY3RvciB0byBlYXJuIG1vcmUgdGhhbiB0aGUgbWVkaWFuIGluY29tZS4gRnVydGhlcm1vcmUsIHdlIHdpbGwgc2VlIHdoaWNoIG9jY3VwYXRpb24gaGFzIHRoZSBsYXJnZXN0L3NtYWxsZXN0ICJiZWxvdyBtZWRpYW4gZ3JvdXAiIHdpdGhpbiBlYWNoIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQuDQoNCldlIGRpdmlkZWQgZmVtYWxlIGludG8gMiBncm91cHMgKD49JDYwLDAwMCB2cyA8NjAsMDAwKSB1c2luZyB3ZWlnaHRlZCBtZWRpYW4gaW5jb21lIGZvciB3b3JraW5nIGNsYXNzLiAoJDYwLDAwMCkNCldlIHdpbGwgc2VlIHRoZSBwcm9wb3J0aW9uIG9mIHRoZXNlIDIgZ3JvdXBzIGZvciBlYWNoIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQuDQoNCmBgYHtyfQ0KI0NhbGN1bGF0ZSB3ZWlnaHRlZCBtZWRpYW4gdG8gc3BsaXQgaW5jb21lIGJlbG93L2Fib3ZlDQpEYXRhX3c8LXN2eWRlc2lnbihpZCA9IH4xLCB3ZWlnaHRzID0gfkRhdGEkV2VpZ2h0LCBkYXRhID0gRGF0YSkNCnN2eXF1YW50aWxlKH5EYXRhJEluY29tZSwgRGF0YV93LCBjKC4yNSwuNSwuNzUpKQ0KIyNNZWRpYW4gaW5jb21lPSQ2MDAwMA0KDQojc3BsaXQgaW5jb21lIGJlbG93L2Fib3ZlDQpEYXRhJEluY29tZV9tPC1pZmVsc2UoRGF0YSRJbmNvbWU+PTYwMDAwLCI+PSQ2MCwwMDAiLCI8JDYwLDAwMCIpDQoNCkRhdGFfd29tZW4yPC1zdWJzZXQoRGF0YSxHZW5kZXI9PScyJykNCmF0dGFjaChEYXRhX3dvbWVuMikNCkRhdGFfd29tZW4yPC1kYXRhLmZyYW1lKEVkdWNhdGlvbixPY2N1cGF0aW9uLEluY29tZV9tLFdlaWdodCkNCmRldGFjaChEYXRhX3dvbWVuMikNCg0KI2dldCB0aGUgc3VtbWFyeSB0YWJsZS1lZHVjYXRpb24NCkRhdGFfd29tZW5fdzwtc3Z5ZGVzaWduKGlkID0gfjEsIHdlaWdodHMgPSB+RGF0YV93b21lbjIkV2VpZ2h0LCBkYXRhID0gRGF0YV93b21lbjIpDQp0MTwtcHJvcC50YWJsZShzdnl0YWJsZSh+SW5jb21lX20rRWR1Y2F0aW9uLCBEYXRhX3dvbWVuX3cpLDIpDQoNCmJhcnBsb3QodDEsIG1haW4gPSAiQmVsb3cvQWJvdmUgbWVkaWFuIGluY29tZSB3b21lbiBieSBFZHVjYXRpb25hbCBhdHRhaW5tZW50Iixjb2wgPSBjKCJtaXN0eXJvc2UiLCAibGF2ZW5kZXIiKSwNCnhsYWIgPSAiRWR1Y2F0aW9uYWwgYXR0YWlubWVudCIsIG5hbWVzID0gYygifmc4IiwgImc5fm5vZGVncmVlIiwiYXNzL2JhY2giLCJwcm9mL21hcyIsImRvYyIpLCANCnlsYWIgPSAicHJvcG9ydGlvbiIsIGxlZ2VuZCA9IGMoIjwkNjAsMDAwIiwgIj49JDYwLDAwMCIpLCANCmFyZ3MubGVnZW5kID0gbGlzdCh0aXRsZSA9ICJpbmNvbWUiLCB4ID0gInRvcHJpZ2h0IiwgY2V4ID0gMSksIHlsaW0gPSBjKDAsIDEuNSkpDQpgYGANCg0KT2JzZXJ2YXRpb25zOg0KDQoxLiBXaXRob3V0IGNvbGxlZ2UgZGVncmVlLCBhYm91dCA4MCUgb2YgdGhlbSBlYXJuIGxlc3MgdGhhbiBtZWRpYW4gaW5jb21lLg0KDQoyLiBXaXRoIG1hc3RlcidzIG9yIGRvY3RvcidzIGRlZ3JlZSwgYWJvdXQgNDAlIG9mIHRoZW0gZWFybiBsZXNzIHRoYW4gbWVkaWFuIGluY29tZS4NCg0KDQpOZXh0LCB3ZSB1c2UgYSBsaW5lYXIgcmVncmVzc2lvbi4NCmBgYHtyfQ0KZml0X2VkdTwtc3Z5Z2xtKGZhY3RvcihJbmNvbWVfbSkgfiBmYWN0b3IoRWR1Y2F0aW9uKSwgZGVzaWduID0gRGF0YV93b21lbl93LGZhbWlseT1iaW5vbWlhbCkNCnN1bW1hcnkoZml0X2VkdSkNCg0KYGBgDQpPYnNlcnZhdGlvbnM6DQoNCjEuIGZhY3RvcjIgKGdyYWRlOX5jb2xsZWdlX25vX2RlZ3JlZSkgaXMgbm90IHNpZ25pZmljYW50Lg0KDQoyLiBJbnRlcnByZXRhdGlvbiBmb3IgZmFjdG9yMzogImFzc29jaWF0ZS9iYWNoZWxvcidzIGRlZ3JlZSIsIHZlcnN1cyAifmdyYWRlOCIoYmFzZWxpbmUpLCBtdWx0aXBsaWVzIHRoZSBvZGRzIG9mIGJlaW5nICI+PSQ2MDAwMCIgZ3JvdXAgYnkgZXhwKDAuOTQzNzIpDQoNCjMuIFdlIGNhbiBhcHBseSB0aGUgc2FtZSBpbnRlcnByZXRhdGlvbiBmb3IgZmFjdG9yIDQsNSw2Lg0KDQo0LiBXaXRoaW4gY29sbGVnZSwgbWFzdGVyLCBkb2N0b3IncyBkZWdyZWUsIHRoZSBjaGFuY2Ugb2YgYmVpbmcgaW4gIj49JDYwMDAwIiBncm91cCBpbmNyZWFzZXMgYXQgaGlnaGVyIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQuDQoNCjUuIEhvd2V2ZXIsIHRoZSBnYXAgYmV0d2VlbiBtYXN0ZXIncyBhbmQgZG9jdG9yJ3MgZGVncmVlIGlzIHJlbGF0aXZlbHkgc21hbGwuDQoNCg0KVG8gZnV0aGVyIHVuZGVyc3RhbmQgdGhlIGVmZmVjdCwgd2UgYXJlIGdvaW5nIHRvIGJyZWFrIGRvd24gZWFjaCBlZHVjYXRpb24gYnkgb2NjdXBhdGlvbi4NCmBgYHtyfQ0KdDI8LXByb3AudGFibGUoc3Z5dGFibGUofkluY29tZV9tK09jY3VwYXRpb24rRWR1Y2F0aW9uLCBEYXRhX3dvbWVuX3cpLGMoMiwzKSkNCiNicmVhayBkb3duIGludG8gb2NjdXBhdGlvbg0KIyMjfmdyYWRlOA0KYmFycGxvdCh0MlssLDFdLG1haW4gPSAifmdyYWRlOCwgYnkgb2NjdXBhdGlvbiIsY29sID0gYygibWlzdHlyb3NlIiwgIndoaXRlIiksDQp4bGFiID0gIm9jY3VwYXRpb24iLCBuYW1lcyA9IGMoJ01HUicsICdDTU0nLCAnRklOJywgJ0xHTCcsICdNRUQnICwgJ0JVUycsICdFTkcnLCAnU0NJJyksIA0KeWxhYiA9ICJwcm9wb3J0aW9uIiwgbGVnZW5kID0gYygiPCQ2MCwwMDAiLCAiPj0kNjAsMDAwIiksIA0KYXJncy5sZWdlbmQgPSBsaXN0KHRpdGxlID0gIkluY29tZSIsIHggPSAidG9wcmlnaHQiLCBjZXggPSAxKSwgeWxpbSA9IGMoMCwgMS41KSkNCg0KYGBgDQpPYnNlcnZhdGlvbnM6DQoNCjEuIFdpdGhpbiAifmdyYWRlOCIsICJGSU46ZmluYW5jZSIgaGFzIHRoZSBsYXJnZXN0IDwkNjAsMDAwIGdyb3VwLg0KDQoyLiAiQ01NOmNvbXB1dGVyIG9jY3MiIGhhcyB0aGUgc21hbGxlc3QgPCQ2MCwwMDAgZ3JvdXAuDQoNCg0KYGBge3IgZWNobyA9IEZBTFNFfQ0KIyMjZ3JhZGU5fmNvbGxlZ2Vfbm9fZGVncmVlDQpiYXJwbG90KHQyWywsMl0sbWFpbiA9ICJncmFkZTl+Y29sbGVnZV9ub19kZWdyZWUsIGJ5IG9jY3VwYXRpb24iLGNvbCA9IGMoIm1pc3R5cm9zZSIsICJ3aGl0ZSIpLA0KeGxhYiA9ICJvY2N1cGF0aW9uIiwgbmFtZXMgPSBjKCdNR1InLCAnQ01NJywgJ0ZJTicsICdMR0wnLCAnTUVEJyAsICdCVVMnLCAnRU5HJywgJ1NDSScpLCANCnlsYWIgPSAicHJvcG9ydGlvbiIsIGxlZ2VuZCA9IGMoIjwkNjAsMDAwIiwgIj49JDYwLDAwMCIpLCANCmFyZ3MubGVnZW5kID0gbGlzdCh0aXRsZSA9ICJJbmNvbWUiLCB4ID0gInRvcHJpZ2h0IiwgY2V4ID0gMSksIHlsaW0gPSBjKDAsIDEuNSkpDQoNCmBgYA0KT2JzZXJ2YXRpb25zOg0KDQoxLiBXaXRoaW4gImdyYWRlOX5jb2xsZWdlX25vX2RlZ3JlZSIsICJTQ0k6c2NpZW5jZSIgaGFzIHRoZSBsYXJnZXN0IDwkNjAsMDAwIGdyb3VwLg0KDQoyLiAiQ01NOmNvbXB1dGVyIG9jY3MiIGhhcyB0aGUgc21hbGxlc3QgPCQ2MCwwMDAgZ3JvdXAuDQoNCmBgYHtyIGVjaG8gPSBGQUxTRX0NCiMjI2Fzc29jaWF0ZS9iYWNoZWxvcg0KYmFycGxvdCh0MlssLDNdLG1haW4gPSAiYXNzb2NpYXRlL2JhY2hlbG9yLCBieSBvY2N1cGF0aW9uIixjb2wgPSBjKCJtaXN0eXJvc2UiLCAid2hpdGUiKSwNCnhsYWIgPSAib2NjdXBhdGlvbiIsIG5hbWVzID0gYygnTUdSJywgJ0NNTScsICdGSU4nLCAnTEdMJywgJ01FRCcgLCAnQlVTJywgJ0VORycsICdTQ0knKSwgDQp5bGFiID0gInByb3BvcnRpb24iLCBsZWdlbmQgPSBjKCI8JDYwLDAwMCIsICI+PSQ2MCwwMDAiKSwgDQphcmdzLmxlZ2VuZCA9IGxpc3QodGl0bGUgPSAiSW5jb21lIiwgeCA9ICJ0b3ByaWdodCIsIGNleCA9IDEpLCB5bGltID0gYygwLCAxLjUpKQ0KDQpgYGANCk9ic2VydmF0aW9uczoNCg0KMS4gV2l0aGluICJhc3NvY2lhdGUvYmFjaGVsb3IiLCAiTEdMOmxlZ2FsIiBoYXMgdGhlIGxhcmdlc3QgPCQ2MCwwMDAgZ3JvdXAuDQoNCjIuICJDTU06IGNvbXB1dGVyIG9jY3MiIGhhcyB0aGUgc21hbGxlc3QgPCQ2MCwwMDAgZ3JvdXAuDQoNCmBgYHtyIGVjaG8gPSBGQUxTRX0NCiMjI21hc3Rlci9wcm9mZXNzaW9uYWwNCmJhcnBsb3QodDJbLCw0XSxtYWluID0gIm1hc3RlciwgYnkgb2NjdXBhdGlvbiIsY29sID0gYygibWlzdHlyb3NlIiwgIndoaXRlIiksDQp4bGFiID0gIm9jY3VwYXRpb24iLCBuYW1lcyA9IGMoJ01HUicsICdDTU0nLCAnRklOJywgJ0xHTCcsICdNRUQnICwgJ0JVUycsICdFTkcnLCAnU0NJJyksIA0KeWxhYiA9ICJwcm9wb3J0aW9uIiwgbGVnZW5kID0gYygiPCQ2MCwwMDAiLCAiPj0kNjAsMDAwIiksIA0KYXJncy5sZWdlbmQgPSBsaXN0KHRpdGxlID0gIkluY29tZSIsIHggPSAidG9wcmlnaHQiLCBjZXggPSAxKSwgeWxpbSA9IGMoMCwgMS41KSkNCg0KYGBgDQpPYnNlcnZhdGlvbnM6DQoNCjEuIFdpdGhpbiAiTWFzdGVyIiwgIkxHTDpsZWdhbCIgaGFzIHRoZSBsYXJnZXN0IDwkNjAsMDAwIGdyb3VwLg0KDQoyLiAiQ01NOmNvbXB1dGVyIG9jY3MiIGhhcyB0aGUgc21hbGxlc3QgPCQ2MCwwMDAgZ3JvdXAuDQoNCmBgYHtyIGVjaG8gPSBGQUxTRX0NCiNkb2N0b3INCmJhcnBsb3QodDJbLCw1XSxtYWluID0gImRvY3RvciwgYnkgb2NjdXBhdGlvbiIsY29sID0gYygibWlzdHlyb3NlIiwgIndoaXRlIiksDQp4bGFiID0gIm9jY3VwYXRpb24iLCBuYW1lcyA9IGMoJ01HUicsICdDTU0nLCAnRklOJywgJ0xHTCcsICdNRUQnICwgJ0JVUycsICdFTkcnLCAnU0NJJyksIA0KeWxhYiA9ICJwcm9wb3J0aW9uIiwgbGVnZW5kID0gYygiPCQ2MCwwMDAiLCAiPj0kNjAsMDAwIiksIA0KYXJncy5sZWdlbmQgPSBsaXN0KHRpdGxlID0gIkluY29tZSIsIHggPSAidG9wcmlnaHQiLCBjZXggPSAxKSwgeWxpbSA9IGMoMCwgMS41KSkNCiMjTUdSIGlzIHRoZSBiZXN0LCBMR0wgaXMgdGhlIHdvcnN0DQpgYGANCk9ic2VydmF0aW9uczoNCg0KMS4gV2l0aGluICJEb2N0b3IiLCAiTEdMOmxlZ2FsIiBoYXMgdGhlIGxhcmdlc3QgPCQ2MCwwMDAgZ3JvdXAuDQoNCjIuICJDTU06Y29tcHV0ZXIgb2NjcyIgaGFzIHRoZSBzbWFsbGVzdCA8JDYwLDAwMCBncm91cC4NCg0KQ29uY2x1c2lvbnM6DQoNCjEuIFdvbWVuIHdpdGhvdXQgY29sbGVnZSBkZWdyZWUgaXMgbW9yZSBsaWtlbHkgdG8gZWFybiBsZXNzIHRoYW4gbWVkaWFuIGluY29tZS4NCg0KMi4gKC0pIEF0IGFueSBlZHVjYXRpb25hbCBhdHRhaW5tZW50LENNTTpjb21wdXRlciBvY2NzIGhhcyB0aGUgc21hbGxlc3QgPCQ2MCwwMDAgZ3JvdXAuDQoNCjMuICgrKSBXaXRoIHRoZSBiYWNoZWxvci9tYXN0ZXIvZG9jdG9yJ3MgZGVncmVlIExHTDpsZWdhbCBoYXMgdGhlIGxhcmdlc3QgPj0kNjAsMDAwIGdyb3VwLg0KICANCiAgDQogIA0KIyBSZWdpb25hbA0KDQpZb3UgY2Fubm90IGNob29zZSB3aGVyZSB5b3Ugd2VyZSBib3JuLCBidXQgeW91IGNhbiBjaG9vc2Ugd2hlcmUgeW91IGxpdmUuIERpZmZlcmVudCBwbGFjZXMgc2VuZHMgZGlmZmVyZW50IG1lc3NhZ2VzIGFuZCBhdHRyYWN0cyBkaWZmZXJlbnQgcGVvcGxlLiBJbiB0aGlzIHNlY3Rpb24gd2UgYXJlIGludGVyZXN0ZWQgdG8gc2VlIHJlZ2lvbmFsIGVmZmVjdCBvbiB3b21lbidzIGluY29tZSBpbiB0aGUgVVMuIFRoZSBtYWluIHF1ZXN0aW9uIGhlcmUgaXM6IGluIHdoaWNoIGxvY2F0aW9ucyBhcmUgd29tZW4gYmV0dGVyIG9yIHdvcnNlIG9mZj8NCg0KRmlyc3QsIHdlIHdhbnQgdG8gbG9vayBhdCB3b21lbidzIGluY29tZSBib3hwbG90cyBpbiBhbGwgNCByZWdpb25zIHRvIGJldHRlciB1bmRlcnN0YW5kIHdvbWVuJ3MgaW5jb21lIGRpc3RyaWJ1dGlvbi4gDQoNCmBgYHtyLGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KRFc9RGF0YVtEYXRhJEdlbmRlcj09MiwgXQ0KDQojIFJlY29kZSBTdGF0ZSBOYW1lcyBiZWZvcmUgYm94cGxvdA0Kc3RhdGVuYW1lcyA8LSByZWFkLmNzdihmaWxlLmNob29zZSgpLGhlYWRlcj1UUlVFKQ0KbmFtZXMoRFcpWzldPC0iY29kZSINCkRXLm4gPC0gbWVyZ2UoRFcsIHN0YXRlbmFtZXMsIGJ5PSJjb2RlIikNCg0KIyBib3hwbG90IG9mIGVhY2ggcmVnaW9uIHRvIHNlZSBkaXN0cmlidXRpb24NCnBsb3RfbHkoRFcsIHggPSBJbmNvbWUsIGNvbG9yID0gUmVnaW9uLCB0eXBlID0gImJveCIpDQpgYGANClRoZSBib3hwbG90cyBvZiB3b21lbidzIGluY29tZSBzaG93IHRoYXQgZGVzcGl0ZSB0aGF0IGFsbCBkaXN0cmlidXRpb25zIGFyZSBoaWdobHkgc2tld2VkIHRvIHRoZSByaWdodCwgdGhlIE5vcnRoZWFzdCBSZWdpb24gaGFzIHRoZSBoaWdoZXN0IHdvbWVuJ3MgaW5jb21lIGxldmVsIG9mIGFsbCA0IHJlZ2lvbnMsIGZvbGxvd2VkIGJ5IHRoZSBXZXN0OyBNaWR3ZXN0IGhhcyB0aGUgbG93ZXN0IHdvbWVuJ3MgaW5jb21lIGxldmVsLCB3aGVyZWFzIFNvdXRoIGlzIG9ubHkgc2xpZ2h0bHkgYmV0dGVyIG9mZiB0aGFuIHRoYXQuIFRoZW4gd2Ugd2lsbCBicmVhayBkb3duIHRvIHN0YXRlIGxldmVsIHRvIGludmVzdGlnYXRlIGZ1cnRoZXIgb24gd29tZW4ncyBpbmNvbWUgbGV2ZWwuDQoNCkluY29tZSBsZXZlbHMgY2FuIGJlIGFmZmVjdGVkIGJ5IG1hbnkgdGhpbmdzLiBDb3N0IG9mIGxpdmluZyBpcyBvbmUgb2YgdGhlbS4gRm9yIGV4YW1wbGUsIEluIE5ldyBZb3JrLCBldmVydGhpbmcgY29zdCBhIGxpdHRsZSBtb3JlIHRoYW4gbWFueSBvdGhlciBwYXJ0cyBvZiB0aGUgVVMsIHNvIHBlb3BsZSB3aWxsIG9ubHkgdGhyaXZlIGJ5IGVhcm5pbmcgbW9yZSBtb25leS4gVGhlcmVmb3JlLCBpbiBvcmRlciB0byByZW1vdmUgdGhlIGVmZmVjdCBvZiBjb3N0IG9mIGxpdmluZyB0aGF0IGRpZmZlcnMgaW4gZGlmZmVyZW50IHN0YXRlcywgd2UgY2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIG1lZGlhbiBvZiBlYWNoIHdvbWFuJ3MgaW5jb21lIGJ5IHN0YXRlIGFuZCBkcmF3IGJveHBsb3QgYWNjb3JkaW5nIHRvIHRoYXQuDQoNCmBgYHtyLGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naG9sZCd9DQojcGVyY2VudGFnZSBtZWRpYW4gb2Ygd29tZW4gYW5kIG1lbiBpbiBlYWNoIHN0YXRlIHRvIHJlbW92ZSBjb3N0IG9mIGxpdmluZw0KR2VuTWVkaWFuPWFnZ3JlZ2F0ZShJbmNvbWV+U3RhdGUsRGF0YSxtZWRpYW4pDQpuYW1lcyhHZW5NZWRpYW4pWzFdPC0iY29kZSINCkdlbk1lZGlhbiA8LSBtZXJnZShHZW5NZWRpYW4sIHN0YXRlbmFtZXMsIGJ5PSJjb2RlIikNCkFsbE1lZGlhbj1HZW5NZWRpYW4kSW5jb21lW21hdGNoKERXLm4kbmFtZSxHZW5NZWRpYW4kbmFtZSldDQpJbmNvbWVTdGF0ZT1jYmluZChEVy5uJEluY29tZS9BbGxNZWRpYW4sRFcubiRuYW1lKQ0KY29sbmFtZXMoSW5jb21lU3RhdGUpPC1jKCJQZXJjZW50YWdlX29mX01lZGlhbiIsIlN0YXRlIikNClBlcmM9YXMuZGF0YS5mcmFtZShJbmNvbWVTdGF0ZSkNClBlcmMkUGVyY2VudGFnZV9vZl9NZWRpYW4gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoUGVyYyRQZXJjZW50YWdlX29mX01lZGlhbikpDQpwbG90X2x5KFBlcmMsIHkgPSBQZXJjZW50YWdlX29mX01lZGlhbiwgY29sb3IgPSBTdGF0ZSwgdHlwZSA9ICJib3giLCB0aXRsZSA9ICIyMDE0IFdvbWVucyBQZXJjZW50YWdlIG9mIE1lZGlhbiBJbmNvbWUgYnkgU3RhdGUiKQ0KYGBgDQpGcm9tIHRoaXMgaXJpc2Rlc2NlbnQgYm94cGxvdCBieSBzdGF0ZSwgd2UgY2FuIHNlZSB0aGF0IE5ldyBZb3JrIGRlZmluaXRlbHkgZ29lcyBhaGVhZCAoZGVzcGl0ZSB0aGF0IGl0cyBjb3N0IG9mIGxpdmluZyBpcyBhbHJlYWR5IGhpZ2gpLCBzbyBkb2VzIENvbm5lY3RpY3V0IHdpdGggbW9yZSBsYXJnZSBleHRyZW1lIHZhbHVlczsgaG93ZXZlciBDYWxpZm9ybmlhIGhhcyB0aGUgaGlnaGVzdCB1cHBlciB3aGlza2VyIGFuZCBsYXJnZXN0IHBvcnRpb24gb2YgdXBwZXIgbWlkZGxlIGluY29tZTsgVXRhaCBhbmQgV3lvbWluZyBhcmUgdGhlIHdvcnN0IG9mZi4NCiAgDQpUaGVuIHdlIHdhbnQgdG8gZGVjaWRlIGxvY2F0aW9ucyB3aGVyZSB3b21lbiB3aWxsIHRocml2ZSBtb3N0IGZpbmFuY2lhbGx5IChyZWxhdGl2ZWx5IHRvIG1lbiksIHNvIHdlIHBsb3Qgd29tZW4ncyBtZWRpYW4gb2YgcGVyY2VudGFnZSBpbmNvbWUgYnkgc3RhdGUgaW4gYSBVUyBtYXAsIHdoaWNoIHNob3dzIHRoZSBwZXJjZW50YWdlIG9mIHN0YXRld2lzZSBtZWRpYW4gdGhhdCBoYWxmIG9mIHdvbWVuIGhhcyBpbmNvbWUgYmVsb3cuIEluIHBlcmZlY3QgZXF1YWwtZ2VuZGVyIHNjZW5hcmlvcywgdGhlIHBlcmNlbnRhZ2Ugc2hvdWxkIGJlIDEsIHdoaWNoIG1lYW5zIGhhbGYgb2Ygd29tZW4gaGF2ZSBpbmNvbWUgYmVsb3cgdGhlIGV4YWN0IHN0YXRld2lzZSBtZWRpYW4uDQogICAgDQpgYGB7cixlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hvbGQnfQ0KIyBNYXAgd29tZW4ncyBtZWRpYW4gb2YgcGVyY2VudGFnZSBvZiBtZWRpYW4gYnkgc3RhdGUNClBlcmNNIDwtIGFnZ3JlZ2F0ZShQZXJjZW50YWdlX29mX01lZGlhbn5TdGF0ZSxQZXJjLCBtZWRpYW4pDQpuYW1lcyhQZXJjTSlbMV08LSJuYW1lIg0KUE0gPC0gbWVyZ2UoUGVyY00sIHN0YXRlbmFtZXMsIGJ5PSJuYW1lIikNCg0KIyBsaWdodCBncmV5IGJvdW5kYXJpZXMNCmwgPC0gbGlzdChjb2xvciA9IHRvUkdCKCJ3aGl0ZSIpLCB3aWR0aCA9IDEpDQojIHNwZWNpZnkgc29tZSBtYXAgcHJvamVjdGlvbi9vcHRpb25zDQpnIDwtIGxpc3QoDQogIHNjb3BlID0gJ3VzYScsDQogIHByb2plY3Rpb24gPSBsaXN0KHR5cGUgPSAnYWxiZXJzIHVzYScpLA0KICBzaG93bGFrZXMgPSBUUlVFLA0KICBsYWtlY29sb3IgPSB0b1JHQignd2hpdGUnKQ0KKQ0KcGxvdF9seShQTSwgeiA9IFBlcmNlbnRhZ2Vfb2ZfTWVkaWFuLCBsb2NhdGlvbnMgPSBhYmJyLCB0ZXh0PW5hbWUsIHR5cGUgPSAnY2hvcm9wbGV0aCcsDQogICAgICAgIGxvY2F0aW9ubW9kZSA9ICdVU0Etc3RhdGVzJywgY29sb3IgPSBQZXJjZW50YWdlX29mX01lZGlhbiwgY29sb3JzID0gJ0JsdWVzJywNCiAgICAgICAgbWFya2VyID0gbGlzdChsaW5lID0gbCksIGNvbG9yYmFyID0gbGlzdCh0aXRsZSA9ICJNZWRpYW4gUGVyY2VudGFnZSIpKSAlPiUNCiAgbGF5b3V0KHRpdGxlID0gJzIwMTQgTWVkaWFuIG9mIFdvbWFuIFBlcmNlbnRhZ2UgSW5jb21lIGJ5IFN0YXRlJywgZ2VvID0gZykNCg0KYGBgDQpUaGlzIG1hcCBjbGVhcmx5IHNob3dzIHRoYXQgVXRhaCBpcyB3aGVyZSB3b21lbiB0aHJpdmUgbW9zdCBmaW5hbmNpYWxseSAocmVsYXRpdmVseSB0byBtZW4pLiBIYWxmIG9mIHdvbWVuIGluIFV0YWggaGF2ZSBpbmNvbWUgYmVsb3cgNjguOTclIG9mIHN0YXRlIG1lZGlhbiwgY29tcGFyZWQgdG8gMTAwJSBpbiB0aGUgcGVyZmVjdCBlcXVhbC1nZW5kZXIgc2l0dWF0aW9uLiBTdXJwcmlzaW5nbHkgKGF0IGxlYXN0IHRvIHVzKSwgRC5DLiB0b3BzIGFtb25nIGFsbCBzdGF0ZXMgd2l0aCBhIDkzJSwgZm9sbG93ZWQgYnkgTmV2YWRhIDkyJSBhbmQgQXJpem9uYSA5MCUuDQogIA0KICANCk9ic2VydmF0aW9uOiBXb21lbidzIGluY29tZSBkaXN0cmlidXRpb25zIGluIGVhY2ggc3RhdGUgYXJlIGFsbCBoaWdobHkgc2tld2VkIHRvIHRoZSByaWdodCB3aXRoIGxvdHMgb2YgbGFyZ2UgZXh0cmVtZSB2YWx1ZXMuIA0KICANCjEuIFRoZSBOb3J0aGVhc3QgUmVnaW9uIGhhcyB0aGUgaGlnaGVzdCB3b21lbidzIGluY29tZSBsZXZlbCBvZiBhbGwgNCByZWdpb25zIGluIHRoZSBVUy4NCiAgDQoyLiBBZnRlciBleGNsdWRpbmcgc3RhdGV3aXNlIGRpZmZlcmVuY2VzIGUuZy4gY29zdCBvZiBsaXZpbmcsIHdvbWVuIGluIE5ldyBZb3JrIGFuZCBDb25uZWN0aWN1dCB0ZW5kIHRvIGhhdmUgaGlnaGVyIGluY29tZXMsIENhbGlmb3JuaWEgaGFzIHRoZSBoaWdoZXN0IHVwcGVyIHdoaXNrZXIgYW5kIGxhcmdlc3QgcG9ydGlvbiBvZiB1cHBlciBtaWRkbGUgaW5jb21lLCBhbmQgVXRhaCBhbmQgV3lvbWluZyBhcmUgdGhlIHdvcnN0IG9mZi4gDQogIA0KMy4gQnkgY29tcGFyaW5nIHdvbWVuJ3MgaW5jb21lIG1lZGlhbnMgd2l0aCBzdGF0ZSBtZWRpYW5zLCB3ZSBzZWUgdGhhdCBoYWxmIG9mIFV0YWgncyB3b21lbiBoYXZlIGluY29tZSBiZWxvdyA2OSUgb2Ygc3RhdGUgbWVkaWFuLCB3aGljaCBpcyB0aGUgbG93ZXN0IHBlcmNlbnRhZ2UgYW1vbmcgYWxsIHN0YXRlcy4gV29tYW4gaW4gRC5DLiwgTmV2YWRhLCBhbmQgQXJpem9uYSBoYXZlIGluY29tZSBtZWRpYW5zIGNsb3Nlc3QgdG8gc3RhdGUgbWVkaWFuLCB3aXRoIHBlcmNlbnRhZ2UgYWJvdmUgOTAlLCB3aGVyZWFzIG90aGVyIHN0YXRlcycgYXJlIG11Y2ggbG93ZXIuDQogICAgDQogICAgDQojUmFjZQ0KDQpPdmVyIHRoZSB5ZWFycywgdGhlcmUgaGFzIGJlZW4gYW4gaW5jcmVhc2UgYXdhcmVuZXNzIG9uIHRoZSB3b21lbiB3YWdlIGdhcCBhbmQgcmFjaWFsIHNvY2lhbCBpc3N1ZXMuIFdlIHdhbnRlZCB0byB1bmRlcnN0YW5kIHRoZSBlZmZlY3RzIG9mIGEgd29tZW4ncyByYWNlIGNvdWxkIHBvdGVudGlhbGx5IGhhdmUgb24gYSB3b21lbidzIGNhcmVlci4gDQoNCkZpcnN0LCB3ZSBicm9rZSBkb3duIHRoZSBkYXRhIG9mIHdvbWVuIGJ5IHJhY2UuDQpgYGB7cn0NClJhY2VfZnJlcSA8LSBmdGFibGUoRGF0YV9Xb21lbiRSYWNlKQ0KUmFjZV9mcmVxIDwtIGFzLmRhdGEuZnJhbWUoUmFjZV9mcmVxKQ0KDQpwbG90X2x5KFJhY2VfZnJlcSwgbGFiZWxzID0gVmFyMSwgdmFsdWVzID0gRnJlcSwgdHlwZSA9ICJwaWUiLGhvbGUgPSAwLjAsbmFtZSA9ICJSYWNlIikgJT4lDQogIGxheW91dCh0aXRsZSA9ICJQZXJjZW50YWdlIG9mIFdvbWVuIGJ5IFJhY2UiKQ0KYGBgDQpGcm9tIHRoZSBwaWUgY2hhcnQsIHdlIGRldGVybWluZWQgdGhhdCBtYWpvcml0eSBvZiB3b21lbiBpbiB0aGUgd29yayBmb3JjZSBhcmUgd2hpdGUuIFRvIHNlZSBob3cgdGhpcyBjb21wYXJlcyB0byB0aGUgbmF0aW9uYWwgYXZlcmFnZSwgd2UgY29tcGFyZWQgdGhpcyBjaGFydCB0byB0aGUgb3ZlcmFsbCByYWNlIGJyZWFrZG93biBvZiB0aGUgY291bnRyeS4gT3VyIGFzc3VtcHRpb24gaXMgdGhhdCB3b21lbiBzaG91bGQgbWFrZSB1cCBoYWxmIG9mIHRoZSB3b3JraW5nIGZvcmNlIGZvciBhbGwgcmFjZXMuIA0KDQpgYGB7cn0NClJhY2VfZnJlcV9BbGwgPC0gZnRhYmxlKERhdGEkUmFjZSkNClJhY2VfZnJlcV9BbGwgPC0gYXMuZGF0YS5mcmFtZShSYWNlX2ZyZXFfQWxsKQ0KDQpSYWNlX0NvbXBhcmUgPC0gZGF0YS5mcmFtZShSYWNlX2ZyZXEkVmFyMSxSYWNlX2ZyZXEkRnJlcSwwLjUgKlJhY2VfZnJlcV9BbGwkRnJlcSwxMDAqKFJhY2VfZnJlcSRGcmVxLTAuNSAqUmFjZV9mcmVxX0FsbCRGcmVxKS9SYWNlX2ZyZXFfQWxsJEZyZXEpDQpjb2xuYW1lcyhSYWNlX0NvbXBhcmUpIDwtIGMoJ1JhY2UnLCdXb21lbicsJzUwJSBvZiBHZW5lcmFsIHBvcHVsYXRpb24nLCdQZXJjZW50YWdlIERpZmZlcmVuY2UgKCUpJykNClJhY2VfQ29tcGFyZQ0KYGBgDQpPYnNlcnZhdGlvbjoNCg0KMS4gRnJvbSB0aGUgdGFibGUsIHdlIGNhbiBnYXRoZXIgdGhhdCBCbGFjayB3b21lbiBhcmUgMTElIGhpZ2hlciB0aGFuIHRoZSBoYWxmIG9mIHRoZSBCbGFjayB3b3JrZm9yY2UuIFRoaXMgbWVhbnMgbW9yZSBibGFjayB3b21lbiBhcmUgd29ya2luZyB0aGFuIG1hbi4gDQoNCjIuIEFsbCBvdGhlciByYWNlcyBoYXZlIGEgcmVsYXRpdmVseSBzbWFsbCBkaWZmZXJlbmNlLiANCg0KMy4gV29ya2ZvcmNlIGdyb3VwcyB3aXRoIG1vcmUgbWVuIHRoYW4gd29tZW4gYXJlIFdoaXRlLCBBc2lhbiwgYW5kIE90aGVycy4NCg0KDQpXZSBhbHNvIHdhbnQgdG8gbG9vayBpbnRvIGhvdyB3b21lbiBwZXJmb3JtIGluIHRoZSBvY2N1cGF0aW9uLiBXZSBicm9rZSB1cCB0aGlzIGludG8gdGhyZWUgY2F0ZWdvcmllczogDQoNCjEuIFdvbWVuIHdobyBwZXJmb3JtIHVuZGVyIHRoZSB3ZWlnaHRlZCBtZWFuIG9mIHdvbWVuDQoNCjIuIFdvbWVuIHdobyBwZXJmb3JtIGFib3ZlIHRoZSB3ZWlnaHRlZCBtZWFuIG9mIGJvdGggZ2VuZGVycw0KDQozLiBXb21lbiB3aG8gcGVyZm9ybSBhYm92ZSB0aGUgd2VpZ2h0ZWQgbWVhbiBvZiBtZW4gDQoNClRoZXNlIGNhdGVnb3JpZXMgd2lsbCBiZSBjbGFzc2lmaWVkIGFzIGJlbG93LCBtZWV0LCBhbmQgZXhjZWVkIHJlc3BlY3RpdmVseS4gDQpgYGB7cn0NCiNDb21wYXJpbmcgd2l0aCBIaXN0b2dyYW1zDQpEU09SX1cgPC0gZGF0YS5mcmFtZShEYXRhX3NleF9vY2NwX3JhY2Vbd2hpY2goRGF0YV9zZXhfb2NjcF9yYWNlJEdlbmRlcj09MiksXSkNCg0KcCA8LSBnZ3Bsb3QoRFNPUl9XLCBhZXMoeD1SYWNlLHk9TUVBTiwgZmlsbD1mYWN0b3IoUmFjZSkpKSArDQogICAgICAgICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdD0iaWRlbnRpdHkiKSsNCiAgICAgICAgICAgIGZhY2V0X2dyaWQoLiB+IE9jY3VwYXRpb24pKw0KICAgICAgICAgICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IE1FQU4pLGRhdGE9RGF0YV9zZXhfb2NjcF93b21lbikrDQogICAgICAgICAgICBnZW9tX3RleHQoYWVzKDEsMC41LGxhYmVsID0gIldvbWVuJ3MgTWVhbiIpKSsNCiAgICAgICAgICAgIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIGJ5IFJhY2Ugb2YgRmVtYWxlcyBjb21wYXJlZCB0byBXb21lbidzIE1lYW4iKQ0KZ2dwbG90bHkocCkNCmBgYA0KRnJvbSB0aGUgZ3JhcGgsIHdlIG5vdGljZXMgdGhhdCBtYWpvcml0eSBvZiBvY2N1cGF0aW9uIHdlcmUgbm90IG1lZXRpbmcgdGhlIGNyaXRlcmlhLiBUbyBnYWluIGEgYmV0dGVyIHVuZGVyc3RhbmQsIHdlIHRvb2sgaW50byBhY2NvdW50IGhlIHBvcHVsYXRpb24gc2l6ZS4gDQpgYGB7cn0NCnggPC0gZnRhYmxlKERhdGFfV29tZW4kUmFjZSxEYXRhX1dvbWVuJE9jY3VwYXRpb24pDQp4IDwtIGFzLmRhdGEuZnJhbWUoeCkNCnggPC0geFstMzEsXSAjZnJlcXVlbmN5IG9mIHplcm8NCg0KRFNPUl9XX0ZyZXEgPC0gZGF0YS5mcmFtZShEU09SX1cseCRGcmVxKQ0KDQpCYXNlIDwtIGdncGxvdChEU09SX1dfRnJlcSwgYWVzKHg9UmFjZSx5PU1FQU4pLGNvbG91ciA9IGZhY3RvcihEU09SX1dfRnJlcSRSYWNlKSkgKw0KICAgICAgICAgICAgZmFjZXRfZ3JpZCguIH4gT2NjdXBhdGlvbikrDQogICAgICAgICAgICBnZW9tX3BvaW50KGFlcyhzaXplID0gRFNPUl9XX0ZyZXEkeC5GcmVxLGNvbG9yID0gZmFjdG9yKERTT1JfV19GcmVxJFJhY2UpKSkrDQogICAgICAgICAgICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBieSBSYWNlIG9mIEZlbWFsZXMgdXNpbmcgU2l6ZSIpKw0KICAgICAgICAgICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IE1FQU4pLGNvbG91cj0iZGVlcHBpbmsxIixkYXRhPURhdGFfc2V4X29jY3Bfd29tZW4pKw0KICAgICAgICAgICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IE1FQU4pLGNvbG91cj0iYmx1ZSIsZGF0YT1EYXRhX3NleF9vY2NwX21lbikrDQogICAgICAgICAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gTUVBTiksY29sb3VyPSJncmVlbiIsZGF0YT1EYXRhX29jY3UpDQpnZ3Bsb3RseShCYXNlKQ0KDQpgYGANCk9iZXJzZXJ2YXRpb25zOg0KDQoxLiBBc2lhbnMgd29tZW4gZWFybiBzaWduaWZpY2FudGx5IGhpZ2hlciBpbmNvbWUgdGhhbiBvdGhlciByYWNlcy4NCg0KMi4gVGhlIGF2ZXJhZ2UgZm9yIHdvbWVuIGlzIHZlcnkgY2xvc2UgdGhlIFdoaXRlIHdvbWVuIGJlY2F1c2UgdGhleSBhY2NvdW50IGZvciBtb3N0IG9mIHRoZSB3b3JrZm9yY2UuDQoNCjMuIFRoZXJlIGFyZSBubyBncm91cHMgb2Ygd29tZW4gdGhhdCBhcmUgaGlnaGVyIHRoYW4gdGhlIG1lZGlhbiBvZiBtZW4NCg0KRnJvbSB0aGUgcGxvdCwgd2UgYWxzbyBzZWUgYSBsb3Qgb2YgbWlub3JpdHkgZ3JvdXBzIHRvd2FyZCB0aGUgYm90dG9tLiBUaGUgZnJlcXVlbmN5IGZvciB0aGVzZSBmcm91cHMgd2VyZSBvZnRlbiB2ZXJ5IHNtYWxsLiBUbyBoZWxwIGdhaW4gYSBiZXR0ZXIgdW5kZXJzdGFuZGluZywgd2UgdG9vayBvdXQgYWxsIGdyb3VwcyB3aXRoIGxlc3MgdGhhbiA1MCBwZW9wbGUgaW4gdGhlIGNhdGVnb3J5LiANCmBgYHtyfQ0KRFNPUl9XX0ZyZXFfZmlsdGVyZWQgPC0gZmlsdGVyKERTT1JfV19GcmVxLCB4LkZyZXEgPiA1MCkNCg0KQmFzZV9maWxsIDwtIGdncGxvdChEU09SX1dfRnJlcV9maWx0ZXJlZCwgYWVzKHg9UmFjZSx5PU1FQU4pLGNvbG91ciA9IGZhY3RvcihEU09SX1dfRnJlcV9maWx0ZXJlZCRSYWNlKSkgKw0KICAgICAgICAgICAgZmFjZXRfZ3JpZCguIH4gT2NjdXBhdGlvbikrDQogICAgICAgICAgICBnZW9tX3BvaW50KGFlcyhzaXplID0gRFNPUl9XX0ZyZXFfZmlsdGVyZWQkeC5GcmVxLGNvbG9yID0gZmFjdG9yKERTT1JfV19GcmVxX2ZpbHRlcmVkJFJhY2UpKSkrDQogICAgICAgICAgICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBieSBSYWNlIG9mIEZlbWFsZXMgdXNpbmcgU2l6ZSIpKw0KICAgICAgICAgICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IE1FQU4pLGNvbG91cj0iZGVlcHBpbmsxIixkYXRhPURhdGFfc2V4X29jY3Bfd29tZW4pKw0KICAgICAgICAgICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IE1FQU4pLGNvbG91cj0iYmx1ZSIsZGF0YT1EYXRhX3NleF9vY2NwX21lbikrDQogICAgICAgICAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gTUVBTiksY29sb3VyPSJncmVlbiIsZGF0YT1EYXRhX29jY3UpDQpnZ3Bsb3RseShCYXNlX2ZpbGwpDQpgYGANCk9iZXNlcnZhdGlvbnM6DQoNCjEuIEV4Y2VwdCBmb3IgQXNpYW5zIGFuZCBCbGFja3MsIGFsbCBvdGhlciBtaW5vcml0eSBncm91cHMgZWFybmVkIHNpZ25pZmljYW50bHkgbGVzcyB0aGFuIHRoZSBtZWRpYW4uIA0KDQoyLiBCbGFjayBXb21lbiBlYXJuIGxlc3MgdGhhbiBXaGl0ZSB3b21lbnMgZm9yIGFsbCBvY2N1cGF0aW9ucywgZXhjZXB0IGxlZ2FsLg0KDQozLiBMYXd5ZXJzIHdvdWxkIGhhdmUgdGhlIG1vc3QgZXF1YWwgcGF5IHJlbGF0aXZlIHRvIHRoZSByZXN0IG9mIHRoZSBvY2N1cGF0aW9ucy4NCg0KDQpGcm9tIG91ciBhbmFseXNpcywgd2UgbGVhcm5lZCB0aGUgZm9sbG93aW5nIGJyZWFrZG93biBvZiB3b21lbiBpbiB0aGUgd29ya2ZvcmNlOg0KDQpMZXZlbCB8IFJhY2Ugb2YgV29tZW4NCi0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tDQpCZWxvdyB8IEJsYWNrLCBBbWVyaWNhbiBJbmRpYW4sIFRyaWJlIHNwZWNpZmllZCwgTmF0aXZlIEhhd2FpaWFuLCBPdGhlciwgVHdvIG9yIG1vcmUgcmFjZXMNCk1lZXQgfCBBc2lhbiwgV2hpdGUNCkV4Y2VlZCB8IE5vbmUgDQoNCg0KVGhyb3VnaCB0aGVzZSByZXN1bHRzLCB0aGVpciBpcyBhIHNpZ25pZmljYW50IGdhcCBpbiBpbmNvbWUgZm9yIHdvbWVuIHJlZ2FyZGxlc3MgdG8gcmFjZS4gDQoNCg0KI0FwcGVuZGl4DQoNCiMjIFVzaW5nIFN1cnZleSBXZWlnaHRzDQpXZSB3ZXJlIHRyeWluZyB0byBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdG8gdXNlIHN1cnZleSB3ZWlnaHRzPyBXb3VsZCB0aGUgZGF0YSBiZSBzaWduaWZpY2FudGx5IGltcGFjdGVkPw0KYGBge3J9DQojIE9uIFN1cnZleSBXZWlnaHRzDQojIGh0dHA6Ly90b3BoY2l0by5ibG9nc3BvdC5jby5hdC8yMDE0LzA0L3NvY2lhbC1zY2llbmNlLWdvZXMtci13ZWlnaHRlZC1zdXJ2ZXkuaHRtbCBXZSBhc3NpZ24gZXZlcnlvbmUgdGhhdCBkaWQgbWFrZSBpdCBpbnRvIHRoZSBzYW1wbGUgYSB3ZWlnaHQuIFNvIHBlb3BsZSB0aGF0IHR1cm4gb3V0IHRvbyBvZnRlbiBpbiB0aGUgc2FtcGxlIHJlY2VpdmUgYSB3ZWlnaHQgb2YgbGVzcyB0aGFuIDEuIEFuZCB0aG9zZSB0aGF0IHdlIHdlcmUgbm90IGFibGUgdG8gcmVhY2ggZW5vdWdoIG9mIGFyZSB1cHdlaWdodGVkIHdpdGggYSB3ZWlnaHQgbGFyZ2VyIHRoYW4gMS4gUmVzcG9uZGVudHMgdGhhdCBiZWxvbmcgdG8gZ3JvdXBzIHRoYXQgaGF2ZSBiZWVuIHNhbXBsZWQgcGVyZmVjdGx5IHJlY2VpdmUgYSB3ZWlnaHQgb2YgMS4gVGhpcyBzb2x1dGlvbiBpcyBjYWxsZWQgcG9zdC1zdHJhdGlmaWNhdGlvbiwgYmVjYXVzZSBpdCBjb21wdXRlcyB3ZWlnaHRzIGJhc2VkIG9uIGdyb3VwIChvciBzdHJhdHVtKSBjaGFyYWN0ZXJpc3RpY3MsIGxpa2UgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhZ2Ugb3IgZ2VuZGVyIHByb3BvcnRpb25zLg0KDQpEYXRhLncgPSBzdnlkZXNpZ24oaWRzID0gfjEsIGRhdGEgPSBEYXRhLCB3ZWlnaHRzID0gRGF0YSRXZWlnaHQpDQpzdW1tYXJ5KERhdGEudykNCg0KIyBjb21wYXJpc29uIG9mIHRoZSBzZXggcmF0aW9zIGluIHRoZSB1bndlaWdodGVkIGFuZCB0aGUgd2VpZ2h0ZWQgZGF0YSBmcmFtZXM6DQpwcm9wLnRhYmxlKHRhYmxlKERhdGEkR2VuZGVyKSkNCnByb3AudGFibGUoc3Z5dGFibGUofkdlbmRlciwgZGVzaWduID0gRGF0YS53KSkNCg0KIyBSdW4gdGhpcyB0byBzZWUgaG93IGl0IHdvcmtzDQp0YWJsZShEYXRhJEdlbmRlcikNCnN2eXRhYmxlKH5HZW5kZXIsIGRlc2lnbiA9IERhdGEudykNCg0KIyBUYWtlIG15IGludGVyZXN0ZWQgdmFyaWFibGUgJ1N0YXRlJyBhcyBhbiBleGFtcGxlLCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB1bndlaWdodGVkIGFuZCB3ZWlnaHRlZCByYXRpbyBpcyByZWFsbHkgc21hbGwNCnN0YXRlIDwtIGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZSh0YWJsZShEYXRhJFN0YXRlKSkgLSBwcm9wLnRhYmxlKHN2eXRhYmxlKH5TdGF0ZSwgZGVzaWduID0gRGF0YS53KSkpDQpzdGF0ZQ0KDQppbmNvbWUgPC0gYXMuZGF0YS5mcmFtZShwcm9wLnRhYmxlKHRhYmxlKERhdGEkSW5jb21lKSkgLSBwcm9wLnRhYmxlKHN2eXRhYmxlKH5JbmNvbWUsIGRlc2lnbiA9IERhdGEudykpKQ0KaW5jb21lDQoNCiNtZWRpYW4gd2FnZSBmb3IgZWFjaCBvY2N1cGF0aW9uIGJ5IGdlbmRlciAoanVzdCB0byBhY2tub3dsZWRnZSB0aGF0IHRoZXJlICppcyogYSBnZW5kZXIgZ2FwKQ0KI2ZhY3RvciBtYXJyaWFnZSBhbmQgY2hhbmdlIGxhYmVscw0KYGBgDQpGcm9tIG91ciByZXN1bHRzLCB0aGUgc3VydmV5IHdlaWdodHMgd291bGQgYmUgaW5zaWduaWZpY2FudCByZWxhdGl2ZSB0byB0aGUgZGF0YS4gVGhlIGRpZmZlcmVuY2UgZm9yIGVhY2ggaW5jb21lIGxldmVsIGJldHdlZW4gdW53ZWlnaHRlZCBhbmQgd2VpZ2h0ZWQgaXMgdG9vIHNtYWxsLg0KDQo=